diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 79fef93d5e..2dfa275713 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -1,5 +1,6 @@
 using LibHac;
 using LibHac.Account;
+using LibHac.Bcat;
 using LibHac.Common;
 using LibHac.Fs;
 using LibHac.FsSystem;
@@ -18,6 +19,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
+using Ryujinx.HLE.HOS.Services.Arp;
 using Ryujinx.HLE.HOS.Services.Mii;
 using Ryujinx.HLE.HOS.Services.Nv;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
@@ -144,6 +146,9 @@ namespace Ryujinx.HLE.HOS
 
         internal NvHostSyncpt HostSyncpoint { get; private set; }
 
+        internal LibHac.Horizon LibHacHorizonServer { get; private set; }
+        internal HorizonClient LibHacHorizonClient { get; private set; }
+
         public Horizon(Switch device, ContentManager contentManager)
         {
             ControlData = new BlitStruct<ApplicationControlProperty>(1);
@@ -280,6 +285,22 @@ namespace Ryujinx.HLE.HOS
             SurfaceFlinger = new SurfaceFlinger(device);
 
             ConfigurationState.Instance.System.EnableDockedMode.Event += OnDockedModeChange;
+
+            InitLibHacHorizon();
+        }
+
+        private void InitLibHacHorizon()
+        {
+            LibHac.Horizon horizon = new LibHac.Horizon(null, Device.FileSystem.FsServer);
+
+            horizon.CreateHorizonClient(out HorizonClient ryujinxClient).ThrowIfFailure();
+            horizon.CreateHorizonClient(out HorizonClient bcatClient).ThrowIfFailure();
+
+            ryujinxClient.Sm.RegisterService(new LibHacIReader(this), "arp:r").ThrowIfFailure();
+            new BcatServer(bcatClient);
+
+            LibHacHorizonServer = horizon;
+            LibHacHorizonClient = ryujinxClient;
         }
 
         private void OnDockedModeChange(object sender, ReactiveEventArgs<bool> e)
diff --git a/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs b/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs
new file mode 100644
index 0000000000..77f02e8d23
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Arp/LibHacIReader.cs
@@ -0,0 +1,52 @@
+using LibHac;
+using LibHac.Arp.Impl;
+using LibHac.Ncm;
+using LibHac.Ns;
+using System;
+
+using ApplicationId = LibHac.ApplicationId;
+
+namespace Ryujinx.HLE.HOS.Services.Arp
+{
+    class LibHacIReader : IReader
+    {
+        private Horizon System { get; }
+
+        public LibHacIReader(Horizon system)
+        {
+            System = system;
+        }
+
+        public Result GetApplicationLaunchProperty(out LibHac.Arp.ApplicationLaunchProperty launchProperty, ulong processId)
+        {
+            launchProperty = new LibHac.Arp.ApplicationLaunchProperty();
+
+            launchProperty.BaseStorageId = StorageId.BuiltInUser;
+            launchProperty.ApplicationId = new ApplicationId(System.TitleId);
+
+            return Result.Success;
+        }
+
+        public Result GetApplicationLaunchPropertyWithApplicationId(out LibHac.Arp.ApplicationLaunchProperty launchProperty,
+            ApplicationId applicationId)
+        {
+            launchProperty = new LibHac.Arp.ApplicationLaunchProperty();
+
+            launchProperty.BaseStorageId = StorageId.BuiltInUser;
+            launchProperty.ApplicationId = applicationId;
+
+            return Result.Success;
+        }
+
+        public Result GetApplicationControlProperty(out ApplicationControlProperty controlProperty, ulong processId)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Result GetApplicationControlPropertyWithApplicationId(out ApplicationControlProperty controlProperty,
+            ApplicationId applicationId)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs
index ec34f5407e..ac1abc3521 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/IServiceCreator.cs
@@ -1,18 +1,25 @@
+using LibHac;
+using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator;
 using Ryujinx.HLE.HOS.Services.Arp;
 
 namespace Ryujinx.HLE.HOS.Services.Bcat
 {
-    [Service("bcat:a")]
-    [Service("bcat:m")]
-    [Service("bcat:u")]
-    [Service("bcat:s")]
+    [Service("bcat:a", "bcat:a")]
+    [Service("bcat:m", "bcat:m")]
+    [Service("bcat:u", "bcat:u")]
+    [Service("bcat:s", "bcat:s")]
     class IServiceCreator : IpcService
     {
-        public IServiceCreator(ServiceCtx context) { }
+        private LibHac.Bcat.Detail.Ipc.IServiceCreator _base;
+
+        public IServiceCreator(ServiceCtx context, string serviceName)
+        {
+            context.Device.System.LibHacHorizonClient.Sm.GetService(out _base, serviceName).ThrowIfFailure();
+        }
 
         [Command(0)]
-        // CreateBcatService(u64, pid) -> object<nn::bcat::detail::ipc::IBcatService>
+        // CreateBcatService(pid) -> object<nn::bcat::detail::ipc::IBcatService>
         public ResultCode CreateBcatService(ServiceCtx context)
         {
             // TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId.
@@ -30,21 +37,36 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
         }
 
         [Command(1)]
-        // CreateDeliveryCacheStorageService(u64, pid) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
+        // CreateDeliveryCacheStorageService(pid) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
         public ResultCode CreateDeliveryCacheStorageService(ServiceCtx context)
         {
-            // TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId.
-            //       Add an instance of nn::bcat::detail::service::core::ApplicationStorageManager who load "bcat-dc-X:/" system save data,
-            //       return ResultCode.NullSaveData if failed.
-            //       Where X depend of the ApplicationLaunchProperty stored in an array (range 0-3).
-            //       Add an instance of nn::bcat::detail::service::ServiceMemoryManager.
+            ulong pid = context.RequestData.ReadUInt64();
 
-            MakeObject(context, new IDeliveryCacheStorageService(context, ApplicationLaunchProperty.GetByPid(context)));
+            Result rc = _base.CreateDeliveryCacheStorageService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService serv, pid);
 
-            // NOTE: If the IDeliveryCacheStorageService is null this error is returned, Doesn't occur in our case. 
-            //       return ResultCode.NullObject;
+            if (rc.IsSuccess())
+            {
+                MakeObject(context, new IDeliveryCacheStorageService(context, serv));
+            }
 
-            return ResultCode.Success;
+            return (ResultCode)rc.Value;
+        }
+
+        [Command(2)]
+        // CreateDeliveryCacheStorageServiceWithApplicationId(nn::ApplicationId) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
+        public ResultCode CreateDeliveryCacheStorageServiceWithApplicationId(ServiceCtx context)
+        {
+            ApplicationId applicationId = context.RequestData.ReadStruct<ApplicationId>();
+
+            Result rc = _base.CreateDeliveryCacheStorageServiceWithApplicationId(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService serv,
+               applicationId);
+
+            if (rc.IsSuccess())
+            {
+                MakeObject(context, new IDeliveryCacheStorageService(context, serv));
+            }
+
+            return (ResultCode)rc.Value;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs
new file mode 100644
index 0000000000..ce5c575e34
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheDirectoryService.cs
@@ -0,0 +1,63 @@
+using LibHac;
+using LibHac.Bcat;
+using Ryujinx.Common;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
+{
+    class IDeliveryCacheDirectoryService : IpcService, IDisposable
+    {
+        private LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService _base;
+
+        public IDeliveryCacheDirectoryService(LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService baseService)
+        {
+            _base = baseService;
+        }
+
+        [Command(0)]
+        // Open(nn::bcat::DirectoryName)
+        public ResultCode Open(ServiceCtx context)
+        {
+            DirectoryName directoryName = context.RequestData.ReadStruct<DirectoryName>();
+
+            Result result = _base.Open(ref directoryName);
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(1)]
+        // Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>)
+        public ResultCode Read(ServiceCtx context)
+        {
+            long position = context.Request.ReceiveBuff[0].Position;
+            long size = context.Request.ReceiveBuff[0].Size;
+
+            byte[] data = new byte[size];
+
+            Result result = _base.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(data));
+
+            context.Memory.WriteBytes(position, data);
+
+            context.ResponseData.Write(entriesRead);
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(2)]
+        // GetCount() -> u32
+        public ResultCode GetCount(ServiceCtx context)
+        {
+            Result result = _base.GetCount(out int count);
+
+            context.ResponseData.Write(count);
+
+            return (ResultCode)result.Value;
+        }
+
+        public void Dispose()
+        {
+            _base?.Dispose();
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs
new file mode 100644
index 0000000000..a621283f9c
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheFileService.cs
@@ -0,0 +1,76 @@
+using LibHac;
+using LibHac.Bcat;
+using Ryujinx.Common;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
+{
+    class IDeliveryCacheFileService : IpcService, IDisposable
+    {
+        private LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService _base;
+
+        public IDeliveryCacheFileService(LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService baseService)
+        {
+            _base = baseService;
+        }
+
+        [Command(0)]
+        // Open(nn::bcat::DirectoryName, nn::bcat::FileName)
+        public ResultCode Open(ServiceCtx context)
+        {
+            DirectoryName directoryName = context.RequestData.ReadStruct<DirectoryName>();
+            FileName fileName = context.RequestData.ReadStruct<FileName>();
+
+            Result result = _base.Open(ref directoryName, ref fileName);
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(1)]
+        // Read(u64) -> (u64, buffer<bytes, 6>)
+        public ResultCode Read(ServiceCtx context)
+        {
+            long position = context.Request.ReceiveBuff[0].Position;
+            long size = context.Request.ReceiveBuff[0].Size;
+
+            long offset = context.RequestData.ReadInt64();
+
+            byte[] data = new byte[size];
+
+            Result result = _base.Read(out long bytesRead, offset, data);
+
+            context.Memory.WriteBytes(position, data);
+
+            context.ResponseData.Write(bytesRead);
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(2)]
+        // GetSize() -> u64
+        public ResultCode GetSize(ServiceCtx context)
+        {
+            Result result = _base.GetSize(out long size);
+
+            context.ResponseData.Write(size);
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(3)]
+        // GetDigest() -> nn::bcat::Digest
+        public ResultCode GetDigest(ServiceCtx context)
+        {
+            Result result = _base.GetDigest(out Digest digest);
+
+            context.ResponseData.WriteStruct(digest);
+
+            return (ResultCode)result.Value;
+        }
+
+        public void Dispose()
+        {
+            _base?.Dispose();
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
index cad4437052..344eb54e40 100644
--- a/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
+++ b/Ryujinx.HLE/HOS/Services/Bcat/ServiceCreator/IDeliveryCacheStorageService.cs
@@ -1,47 +1,68 @@
-using Ryujinx.HLE.HOS.Services.Arp;
+using LibHac;
+using LibHac.Bcat;
 using System;
-using System.Text;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
 {
-    class IDeliveryCacheStorageService : IpcService
+    class IDeliveryCacheStorageService : IpcService, IDisposable
     {
-        private const int DeliveryCacheDirectoriesLimit    = 100;
-        private const int DeliveryCacheDirectoryNameLength = 32;
+        private LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService _base;
 
-        private string[] _deliveryCacheDirectories = new string[0];
-
-        public IDeliveryCacheStorageService(ServiceCtx context, ApplicationLaunchProperty applicationLaunchProperty)
+        public IDeliveryCacheStorageService(ServiceCtx context, LibHac.Bcat.Detail.Ipc.IDeliveryCacheStorageService baseService)
         {
-            // TODO: Read directories.meta file from the save data (loaded in IServiceCreator) in _deliveryCacheDirectories.
+            _base = baseService;
+        }
+
+        [Command(0)]
+        // CreateFileService() -> object<nn::bcat::detail::ipc::IDeliveryCacheFileService>
+        public ResultCode CreateFileService(ServiceCtx context)
+        {
+            Result result = _base.CreateFileService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheFileService service);
+
+            if (result.IsSuccess())
+            {
+                MakeObject(context, new IDeliveryCacheFileService(service));
+            }
+
+            return (ResultCode)result.Value;
+        }
+
+        [Command(1)]
+        // CreateDirectoryService() -> object<nn::bcat::detail::ipc::IDeliveryCacheDirectoryService>
+        public ResultCode CreateDirectoryService(ServiceCtx context)
+        {
+            Result result = _base.CreateDirectoryService(out LibHac.Bcat.Detail.Ipc.IDeliveryCacheDirectoryService service);
+
+            if (result.IsSuccess())
+            {
+                MakeObject(context, new IDeliveryCacheDirectoryService(service));
+            }
+
+            return (ResultCode)result.Value;
         }
 
         [Command(10)]
         // EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>)
         public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context)
         {
-            long outputPosition = context.Request.ReceiveBuff[0].Position;
-            long outputSize     = context.Request.ReceiveBuff[0].Size;
+            long position = context.Request.ReceiveBuff[0].Position;
+            long size = context.Request.ReceiveBuff[0].Size;
 
-            for (int index = 0; index < _deliveryCacheDirectories.Length; index++)
-            {
-                if (index == DeliveryCacheDirectoriesLimit - 1)
-                {
-                    break;
-                }
+            byte[] data = new byte[size];
 
-                byte[] directoryNameBuffer = Encoding.ASCII.GetBytes(_deliveryCacheDirectories[index]);
+            Result result = _base.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(data));
 
-                Array.Resize(ref directoryNameBuffer, DeliveryCacheDirectoryNameLength);
+            context.Memory.WriteBytes(position, data);
 
-                directoryNameBuffer[DeliveryCacheDirectoryNameLength - 1] = 0x00;
-                
-                context.Memory.WriteBytes(outputPosition + index * DeliveryCacheDirectoryNameLength, directoryNameBuffer);
-            }
+            context.ResponseData.Write(count);
 
-            context.ResponseData.Write(_deliveryCacheDirectories.Length);
+            return (ResultCode)result.Value;
+        }
 
-            return ResultCode.Success;
+        public void Dispose()
+        {
+            _base?.Dispose();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index 8a7d4a0f07..d82fc40226 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -52,7 +52,7 @@
 
   <ItemGroup>
     <PackageReference Include="Concentus" Version="1.1.7" />
-    <PackageReference Include="LibHac" Version="0.10.0" />
+    <PackageReference Include="LibHac" Version="0.11.0" />
     <PackageReference Include="MsgPack.Cli" Version="1.0.1" />
   </ItemGroup>
 
diff --git a/Ryujinx/Ui/GameTableContextMenu.cs b/Ryujinx/Ui/GameTableContextMenu.cs
index 5db34ecbbe..8bead1e3dd 100644
--- a/Ryujinx/Ui/GameTableContextMenu.cs
+++ b/Ryujinx/Ui/GameTableContextMenu.cs
@@ -40,6 +40,7 @@ namespace Ryujinx.Ui
 #pragma warning disable IDE0044
         [GUI] MenuItem _openSaveUserDir;
         [GUI] MenuItem _openSaveDeviceDir;
+        [GUI] MenuItem _openSaveBcatDir;
         [GUI] MenuItem _manageTitleUpdates;
         [GUI] MenuItem _extractRomFs;
         [GUI] MenuItem _extractExeFs;
@@ -61,6 +62,7 @@ namespace Ryujinx.Ui
 
             _openSaveUserDir.Activated    += OpenSaveUserDir_Clicked;
             _openSaveDeviceDir.Activated  += OpenSaveDeviceDir_Clicked;
+            _openSaveBcatDir.Activated    += OpenSaveBcatDir_Clicked;
             _manageTitleUpdates.Activated += ManageTitleUpdates_Clicked;
             _extractRomFs.Activated       += ExtractRomFs_Clicked;
             _extractExeFs.Activated       += ExtractExeFs_Clicked;
@@ -68,6 +70,7 @@ namespace Ryujinx.Ui
 
             _openSaveUserDir.Sensitive   = !Util.IsEmpty(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0;
             _openSaveDeviceDir.Sensitive = !Util.IsEmpty(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0;
+            _openSaveBcatDir.Sensitive   = !Util.IsEmpty(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0;
 
             string ext = System.IO.Path.GetExtension(_gameTableStore.GetValue(_rowIter, 9).ToString()).ToLower();
             if (ext != ".nca" && ext != ".nsp" && ext != ".pfs0" && ext != ".xci")
@@ -516,6 +519,24 @@ namespace Ryujinx.Ui
             OpenSaveDir(titleName, titleIdNumber, filter);
         }
 
+        private void OpenSaveBcatDir_Clicked(object sender, EventArgs args)
+        {
+            string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
+            string titleId   = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
+
+            if (!ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
+            {
+                GtkDialog.CreateErrorDialog("UI error: The selected game did not have a valid title ID");
+
+                return;
+            }
+
+            SaveDataFilter filter = new SaveDataFilter();
+            filter.SetSaveDataType(SaveDataType.Bcat);
+
+            OpenSaveDir(titleName, titleIdNumber, filter);
+        }
+
         private void ManageTitleUpdates_Clicked(object sender, EventArgs args)
         {
             string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
diff --git a/Ryujinx/Ui/GameTableContextMenu.glade b/Ryujinx/Ui/GameTableContextMenu.glade
index 8f71ecf73b..e648b745bf 100644
--- a/Ryujinx/Ui/GameTableContextMenu.glade
+++ b/Ryujinx/Ui/GameTableContextMenu.glade
@@ -23,6 +23,15 @@
         <property name="use_underline">True</property>
       </object>
     </child>
+    <child>
+      <object class="GtkMenuItem" id="_openSaveBcatDir">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Open the folder where the BCAT save for the application is loaded</property>
+        <property name="label" translatable="yes">Open BCAT Save Directory</property>
+        <property name="use_underline">True</property>
+      </object>
+    </child>
     <child>
       <object class="GtkSeparatorMenuItem">
         <property name="visible">True</property>