diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
index f2b62eef54..a18838abef 100644
--- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
+++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
@@ -197,7 +197,7 @@ namespace Ryujinx.HLE.FileSystem.Content
         }
 
         // fs must contain AOC nca files in its root
-        public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId)
+        public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId, IntegrityCheckLevel integrityCheckLevel)
         {
             _virtualFileSystem.ImportTickets(fs);
 
@@ -214,7 +214,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                         continue;
                     }
 
-                    using var pfs0 = nca.OpenFileSystem(0, Switch.GetIntegrityCheckLevel());
+                    using var pfs0 = nca.OpenFileSystem(0, integrityCheckLevel);
 
                     pfs0.OpenFile(out IFile cnmtFile, pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
 
@@ -265,7 +265,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
         public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList();
 
-        public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage)
+        public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
         {
             aocStorage = null;
 
@@ -289,7 +289,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                         return false; // Print error?
                 }
 
-                aocStorage = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()).OpenStorage(NcaSectionType.Data, Switch.GetIntegrityCheckLevel());
+                aocStorage = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()).OpenStorage(NcaSectionType.Data, integrityCheckLevel);
                 
                 return true;
             }
@@ -710,8 +710,6 @@ namespace Ryujinx.HLE.FileSystem.Content
 
             SystemVersion VerifyAndGetVersionZip(ZipArchive archive)
             {
-                IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
-
                 SystemVersion systemVersion = null;
 
                 foreach (var entry in archive.Entries)
@@ -751,7 +749,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                     {
                         Nca metaNca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
 
-                        IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                        IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
@@ -781,7 +779,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                         {
                             Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
 
-                            var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                            var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                             if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                             {
@@ -816,7 +814,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                                 {
                                     Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaNcaStream.AsStorage());
 
-                                    IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                                    IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                                     string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
@@ -873,8 +871,6 @@ namespace Ryujinx.HLE.FileSystem.Content
 
             SystemVersion VerifyAndGetVersion(IFileSystem filesystem)
             {
-                IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
-
                 SystemVersion systemVersion = null;
 
                 CnmtContentMetaEntry[] metaEntries = null;
@@ -887,7 +883,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                     if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta)
                     {
-                        IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                        IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
@@ -905,7 +901,7 @@ namespace Ryujinx.HLE.FileSystem.Content
                     }
                     else if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
                     {
-                        var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                        var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                         if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                         {
@@ -952,7 +948,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                         Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaStorage);
 
-                        IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                        IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                         string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
 
@@ -1004,8 +1000,6 @@ namespace Ryujinx.HLE.FileSystem.Content
 
         public SystemVersion GetCurrentFirmwareVersion()
         {
-            IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
-
             LoadEntries();
 
             lock (_lock)
@@ -1024,7 +1018,7 @@ namespace Ryujinx.HLE.FileSystem.Content
 
                             if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
                             {
-                                var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel);
+                                var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
 
                                 if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
                                 {
diff --git a/Ryujinx.HLE/HLEConfiguration.cs b/Ryujinx.HLE/HLEConfiguration.cs
new file mode 100644
index 0000000000..00c79169c6
--- /dev/null
+++ b/Ryujinx.HLE/HLEConfiguration.cs
@@ -0,0 +1,179 @@
+using LibHac.FsSystem;
+using Ryujinx.Audio.Integration;
+using Ryujinx.Common;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Configuration.Hid;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.FileSystem.Content;
+using Ryujinx.HLE.HOS;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
+using Ryujinx.HLE.HOS.SystemState;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE
+{
+    /// <summary>
+    /// HLE configuration.
+    /// </summary>
+    public class HLEConfiguration
+    {
+        /// <summary>
+        /// The virtual file system used by the FS service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly VirtualFileSystem VirtualFileSystem;
+
+        /// <summary>
+        /// The account manager used by the account service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly AccountManager AccountManager;
+
+        /// <summary>
+        /// The content manager used by the NCM service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly ContentManager ContentManager;
+
+        /// <summary>
+        /// The persistant information between run for multi-application capabilities.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        public readonly UserChannelPersistence UserChannelPersistence;
+
+        /// <summary>
+        /// The GPU renderer to use for all GPU operations.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly IRenderer GpuRenderer;
+
+        /// <summary>
+        /// The audio device driver to use for all audio operations.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly IHardwareDeviceDriver AudioDeviceDriver;
+
+        /// <summary>
+        /// The handler for various UI related operations needed outside of HLE.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly IHostUiHandler HostUiHandler;
+
+        /// <summary>
+        /// Control the memory configuration used by the emulation context.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly MemoryConfiguration MemoryConfiguration;
+
+        /// <summary>
+        /// The system language to use in the settings service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly SystemLanguage SystemLanguage;
+
+        /// <summary>
+        /// The system region to use in the settings service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly RegionCode Region;
+
+        /// <summary>
+        /// Control the initial state of the vertical sync in the SurfaceFlinger service.
+        /// </summary>
+        internal readonly bool EnableVsync;
+
+        /// <summary>
+        /// Control the initial state of the docked mode.
+        /// </summary>
+        internal readonly bool EnableDockedMode;
+
+        /// <summary>
+        /// Control if the Profiled Translation Cache (PTC) should be used.
+        /// </summary>
+        internal readonly bool EnablePtc;
+
+        /// <summary>
+        /// Control LibHac's integrity check level.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly IntegrityCheckLevel FsIntegrityCheckLevel;
+
+        /// <summary>
+        /// Control LibHac's global access logging level. Value must be between 0 and 3.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly int FsGlobalAccessLogMode;
+
+        /// <summary>
+        /// The system time offset to apply to the time service steady and local clocks.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly long SystemTimeOffset;
+
+        /// <summary>
+        /// The system timezone used by the time service.
+        /// </summary>
+        /// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
+        internal readonly string TimeZone;
+
+        /// <summary>
+        /// Control the inital state of the ignore missing services setting.
+        /// If this is set to true, when a missing service is encountered, it will try to automatically handle it instead of throwing an exception.
+        /// </summary>
+        /// TODO: Update this again.
+        public bool IgnoreMissingServices { internal get; set; }
+
+        /// <summary>
+        /// Aspect Ratio applied to the renderer window by the SurfaceFlinger service.
+        /// </summary>
+        public AspectRatio AspectRatio { internal get; set; }
+
+        /// <summary>
+        /// An action called when HLE force a refresh of output after docked mode changed.
+        /// </summary>
+        public Action RefreshInputConfig { internal get; set; }
+
+        public HLEConfiguration(VirtualFileSystem virtualFileSystem,
+                                ContentManager contentManager,
+                                AccountManager accountManager,
+                                UserChannelPersistence userChannelPersistence,
+                                IRenderer gpuRenderer,
+                                IHardwareDeviceDriver audioDeviceDriver,
+                                MemoryConfiguration memoryConfiguration,
+                                IHostUiHandler hostUiHandler,
+                                SystemLanguage systemLanguage,
+                                RegionCode region,
+                                bool enableVsync,
+                                bool enableDockedMode,
+                                bool enablePtc,
+                                IntegrityCheckLevel fsIntegrityCheckLevel,
+                                int fsGlobalAccessLogMode,
+                                long systemTimeOffset,
+                                string timeZone,
+                                bool ignoreMissingServices,
+                                AspectRatio aspectRatio)
+        {
+            VirtualFileSystem = virtualFileSystem;
+            AccountManager = accountManager;
+            ContentManager = contentManager;
+            UserChannelPersistence = userChannelPersistence;
+            GpuRenderer = gpuRenderer;
+            AudioDeviceDriver = audioDeviceDriver;
+            MemoryConfiguration = memoryConfiguration;
+            HostUiHandler = hostUiHandler;
+            SystemLanguage = systemLanguage;
+            Region = region;
+            EnableVsync = enableVsync;
+            EnableDockedMode = enableDockedMode;
+            EnablePtc = enablePtc;
+            FsIntegrityCheckLevel = fsIntegrityCheckLevel;
+            FsGlobalAccessLogMode = fsGlobalAccessLogMode;
+            SystemTimeOffset = systemTimeOffset;
+            TimeZone = timeZone;
+            IgnoreMissingServices = ignoreMissingServices;
+            AspectRatio = aspectRatio;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index 05db567a8f..3832dd3eb2 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -10,7 +10,6 @@ using LibHac.Ns;
 using Ryujinx.Common.Configuration;
 using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS.Kernel.Process;
 using Ryujinx.HLE.Loaders.Executables;
 using Ryujinx.HLE.Loaders.Npdm;
@@ -49,10 +48,7 @@ namespace Ryujinx.HLE.HOS
             "sdk"
         };
 
-        private readonly Switch            _device;
-        private readonly ContentManager    _contentManager;
-        private readonly VirtualFileSystem _fileSystem;
-
+        private readonly Switch _device;
         private string _titleName;
         private string _displayVersion;
         private BlitStruct<ApplicationControlProperty> _controlData;
@@ -66,12 +62,9 @@ namespace Ryujinx.HLE.HOS
 
         public string TitleIdText => TitleId.ToString("x16");
 
-        public ApplicationLoader(Switch device, VirtualFileSystem fileSystem, ContentManager contentManager)
+        public ApplicationLoader(Switch device)
         {
-            _device         = device;
-            _contentManager = contentManager;
-            _fileSystem     = fileSystem;
-
+            _device      = device;
             _controlData = new BlitStruct<ApplicationControlProperty>(1);
         }
 
@@ -79,14 +72,14 @@ namespace Ryujinx.HLE.HOS
         {
             if (romFsFile != null)
             {
-                _fileSystem.LoadRomFs(romFsFile);
+                _device.Configuration.VirtualFileSystem.LoadRomFs(romFsFile);
             }
 
             LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
 
             Npdm metaData = ReadNpdm(codeFs);
 
-            _fileSystem.ModLoader.CollectMods(new[] { TitleId }, _fileSystem.ModLoader.GetModsBasePath());
+            _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { TitleId }, _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath());
 
             if (TitleId != 0)
             {
@@ -209,7 +202,7 @@ namespace Ryujinx.HLE.HOS
         public void LoadXci(string xciFile)
         {
             FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read);
-            Xci        xci  = new Xci(_fileSystem.KeySet, file.AsStorage());
+            Xci        xci  = new Xci(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage());
 
             if (!xci.HasPartition(XciPartitionType.Secure))
             {
@@ -226,7 +219,7 @@ namespace Ryujinx.HLE.HOS
 
             try
             {
-                (mainNca, patchNca, controlNca) = GetGameData(_fileSystem, securePartition, _device.UserChannelPersistence.Index);
+                (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, securePartition, _device.Configuration.UserChannelPersistence.Index);
             }
             catch (Exception e)
             {
@@ -242,9 +235,9 @@ namespace Ryujinx.HLE.HOS
                 return;
             }
 
-            _contentManager.LoadEntries(_device);
-            _contentManager.ClearAocData();
-            _contentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId);
+            _device.Configuration.ContentManager.LoadEntries(_device);
+            _device.Configuration.ContentManager.ClearAocData();
+            _device.Configuration.ContentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
 
             LoadNca(mainNca, patchNca, controlNca);
         }
@@ -260,7 +253,7 @@ namespace Ryujinx.HLE.HOS
 
             try
             {
-                (mainNca, patchNca, controlNca) = GetGameData(_fileSystem, nsp, _device.UserChannelPersistence.Index);
+                (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, nsp, _device.Configuration.UserChannelPersistence.Index);
             }
             catch (Exception e)
             {
@@ -278,8 +271,8 @@ namespace Ryujinx.HLE.HOS
 
             if (mainNca != null)
             {
-                _contentManager.ClearAocData();
-                _contentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId);
+                _device.Configuration.ContentManager.ClearAocData();
+                _device.Configuration.ContentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
 
                 LoadNca(mainNca, patchNca, controlNca);
 
@@ -293,7 +286,7 @@ namespace Ryujinx.HLE.HOS
         public void LoadNca(string ncaFile)
         {
             FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
-            Nca        nca  = new Nca(_fileSystem.KeySet, file.AsStorage(false));
+            Nca        nca  = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
 
             LoadNca(nca, null, null);
         }
@@ -310,7 +303,7 @@ namespace Ryujinx.HLE.HOS
             IStorage    dataStorage = null;
             IFileSystem codeFs      = null;
 
-            (Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_fileSystem, mainNca.Header.TitleId.ToString("x16"), _device.UserChannelPersistence.Index, out _);
+            (Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), _device.Configuration.UserChannelPersistence.Index, out _);
 
             if (updatePatchNca != null)
             {
@@ -323,7 +316,7 @@ namespace Ryujinx.HLE.HOS
             }
 
             // Load program 0 control NCA as we are going to need it for display version.
-            (_, Nca updateProgram0ControlNca) = GetGameUpdateData(_fileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _);
+            (_, Nca updateProgram0ControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _);
 
             // Load Aoc
             string titleAocMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json");
@@ -336,7 +329,7 @@ namespace Ryujinx.HLE.HOS
                 {
                     foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
                     {
-                        _contentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled);
+                        _device.Configuration.ContentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled);
                     }
                 }
             }
@@ -375,7 +368,7 @@ namespace Ryujinx.HLE.HOS
 
             Npdm metaData = ReadNpdm(codeFs);
 
-            _fileSystem.ModLoader.CollectMods(_contentManager.GetAocTitleIds().Prepend(TitleId), _fileSystem.ModLoader.GetModsBasePath());
+            _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(_device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId), _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath());
 
             if (controlNca != null)
             {
@@ -388,7 +381,7 @@ namespace Ryujinx.HLE.HOS
 
             // NOTE: Nintendo doesn't guarantee that the display version will be updated on sub programs when updating a multi program application.
             // BODY: As such, to avoid PTC cache confusion, we only trust the the program 0 display version when launching a sub program.
-            if (updateProgram0ControlNca != null && _device.UserChannelPersistence.Index != 0)
+            if (updateProgram0ControlNca != null && _device.Configuration.UserChannelPersistence.Index != 0)
             {
                 string dummyTitleName = "";
                 BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1);
@@ -402,9 +395,9 @@ namespace Ryujinx.HLE.HOS
             }
             else
             {
-                IStorage newStorage = _fileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
+                IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
 
-                _fileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read));
+                _device.Configuration.VirtualFileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read));
             }
 
             if (TitleId != 0)
@@ -470,7 +463,7 @@ namespace Ryujinx.HLE.HOS
 
         private void LoadExeFs(IFileSystem codeFs, Npdm metaData = null)
         {
-            if (_fileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
+            if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
             {
                 metaData = null; //TODO: Check if we should retain old npdm
             }
@@ -496,7 +489,7 @@ namespace Ryujinx.HLE.HOS
             }
 
             // ExeFs file replacements
-            ModLoadResult modLoadResult = _fileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
+            ModLoadResult modLoadResult = _device.Configuration.VirtualFileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
 
             // collect the nsos, ignoring ones that aren't used
             NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
@@ -507,9 +500,9 @@ namespace Ryujinx.HLE.HOS
                 metaData = modLoadResult.Npdm;
             }
 
-            _fileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
+            _device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
 
-            _contentManager.LoadEntries(_device);
+            _device.Configuration.ContentManager.LoadEntries(_device);
 
             bool usePtc = _device.System.EnablePtc;
 
@@ -528,7 +521,7 @@ namespace Ryujinx.HLE.HOS
 
             ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: programs);
 
-            _fileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
+            _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
         }
 
         public void LoadProgram(string filePath)
@@ -569,7 +562,7 @@ namespace Ryujinx.HLE.HOS
 
                             if (romfsSize != 0)
                             {
-                                _fileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset));
+                                _device.Configuration.VirtualFileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset));
                             }
 
                             if (nacpSize != 0)
@@ -617,7 +610,7 @@ namespace Ryujinx.HLE.HOS
                 executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read), Path.GetFileNameWithoutExtension(filePath));
             }
 
-            _contentManager.LoadEntries(_device);
+            _device.Configuration.ContentManager.LoadEntries(_device);
 
             _titleName   = metaData.TitleName;
             TitleId      = metaData.Aci0.TitleId;
@@ -629,7 +622,7 @@ namespace Ryujinx.HLE.HOS
 
             ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: executable);
 
-            _fileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
+            _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
         }
 
         private Npdm GetDefaultNpdm()
@@ -664,7 +657,7 @@ namespace Ryujinx.HLE.HOS
                     "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
             }
 
-            FileSystemClient fileSystem = _fileSystem.FsClient;
+            FileSystemClient fileSystem = _device.Configuration.VirtualFileSystem.FsClient;
             Result           resultCode = fileSystem.EnsureApplicationCacheStorage(out _, applicationId, ref control);
 
             if (resultCode.IsFailure())
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index d8e1605aee..13d7a2afc4 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -8,8 +8,6 @@ using Ryujinx.Audio.Integration;
 using Ryujinx.Audio.Output;
 using Ryujinx.Audio.Renderer.Device;
 using Ryujinx.Audio.Renderer.Server;
-using Ryujinx.Common;
-using Ryujinx.Configuration;
 using Ryujinx.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS.Font;
 using Ryujinx.HLE.HOS.Kernel;
@@ -111,13 +109,13 @@ namespace Ryujinx.HLE.HOS
         internal LibHac.Horizon LibHacHorizonServer { get; private set; }
         internal HorizonClient LibHacHorizonClient { get; private set; }
 
-        public Horizon(Switch device, ContentManager contentManager, AccountManager accountManager, MemoryConfiguration memoryConfiguration)
+        public Horizon(Switch device)
         {
             KernelContext = new KernelContext(
                 device,
                 device.Memory,
-                memoryConfiguration.ToKernelMemorySize(),
-                memoryConfiguration.ToKernelMemoryArrange());
+                device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
+                device.Configuration.MemoryConfiguration.ToKernelMemoryArrange());
 
             Device = device;
 
@@ -166,8 +164,8 @@ namespace Ryujinx.HLE.HOS
 
             DisplayResolutionChangeEvent = new KEvent(KernelContext);
 
-            AccountManager = accountManager;
-            ContentManager = contentManager;
+            AccountManager = device.Configuration.AccountManager;
+            ContentManager = device.Configuration.ContentManager;
             CaptureManager = new CaptureManager(device);
 
             // TODO: use set:sys (and get external clock source id from settings)
@@ -179,7 +177,7 @@ namespace Ryujinx.HLE.HOS
             TimeSpanType systemTime = TimeSpanType.FromSeconds((long)rtcValue);
 
             // Configure and setup internal offset
-            TimeSpanType internalOffset = TimeSpanType.FromSeconds(ConfigurationState.Instance.System.SystemTimeOffset);
+            TimeSpanType internalOffset = TimeSpanType.FromSeconds(device.Configuration.SystemTimeOffset);
 
             TimeSpanType systemTimeOffset = new TimeSpanType(systemTime.NanoSeconds + internalOffset.NanoSeconds);
 
@@ -219,8 +217,6 @@ namespace Ryujinx.HLE.HOS
 
             SurfaceFlinger = new SurfaceFlinger(device);
 
-            ConfigurationState.Instance.System.EnableDockedMode.Event += OnDockedModeChange;
-
             InitLibHacHorizon();
             InitializeAudioRenderer();
         }
@@ -313,11 +309,11 @@ namespace Ryujinx.HLE.HOS
             LibHacHorizonClient = ryujinxClient;
         }
 
-        private void OnDockedModeChange(object sender, ReactiveEventArgs<bool> e)
+        public void ChangeDockedModeState(bool newState)
         {
-            if (e.NewValue != State.DockedMode)
+            if (newState != State.DockedMode)
             {
-                State.DockedMode = e.NewValue;
+                State.DockedMode = newState;
                 PerformanceState.PerformanceMode = State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
 
                 AppletState.Messages.Enqueue(MessageInfo.OperationModeChanged);
@@ -326,8 +322,7 @@ namespace Ryujinx.HLE.HOS
 
                 SignalDisplayResolutionChange();
 
-                // Reconfigure controllers
-                Device.Hid.RefreshInputConfig(ConfigurationState.Instance.Hid.InputConfig.Value);
+                Device.Configuration.RefreshInputConfig?.Invoke();
             }
         }
 
@@ -388,8 +383,6 @@ namespace Ryujinx.HLE.HOS
         {
             if (!_isDisposed && disposing)
             {
-                ConfigurationState.Instance.System.EnableDockedMode.Event -= OnDockedModeChange;
-
                 _isDisposed = true;
 
                 KProcess terminationProcess = new KProcess(KernelContext);
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
index 7c04a4d1fd..e063314585 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
@@ -57,7 +57,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
             switch (kind)
             {
                 case LaunchParameterKind.UserChannel:
-                    storageData = context.Device.UserChannelPersistence.Pop();
+                    storageData = context.Device.Configuration.UserChannelPersistence.Pop();
                     break;
                 case LaunchParameterKind.PreselectedUser:
                     // Only the first 0x18 bytes of the Data seems to be actually used.
@@ -453,7 +453,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // ClearUserChannel()
         public ResultCode ClearUserChannel(ServiceCtx context)
         {
-            context.Device.UserChannelPersistence.Clear();
+            context.Device.Configuration.UserChannelPersistence.Clear();
 
             return ResultCode.Success;
         }
@@ -464,7 +464,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         {
             AppletAE.IStorage data = GetObject<AppletAE.IStorage>(context, 0);
 
-            context.Device.UserChannelPersistence.Push(data.Data);
+            context.Device.Configuration.UserChannelPersistence.Push(data.Data);
 
             return ResultCode.Success;
         }
@@ -473,7 +473,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
         // GetPreviousProgramIndex() -> s32 program_index
         public ResultCode GetPreviousProgramIndex(ServiceCtx context)
         {
-            int previousProgramIndex = context.Device.UserChannelPersistence.PreviousIndex;
+            int previousProgramIndex = context.Device.Configuration.UserChannelPersistence.PreviousIndex;
 
             context.ResponseData.Write(previousProgramIndex);
 
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 05ad19fb76..fd8844c7ff 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -396,7 +396,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
 
             // We do a mitm here to find if the request is for an AOC.
             // This is because AOC can be distributed over multiple containers in the emulator.
-            if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage))
+            if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel))
             {
                 Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}");
 
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs
index 1e85dbf750..61a12d9ed8 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             Npads       = new NpadDevices(_device, true);
         }
 
-        internal void RefreshInputConfig(List<InputConfig> inputConfig)
+        public void RefreshInputConfig(List<InputConfig> inputConfig)
         {
             ControllerConfig[] npadConfig = new ControllerConfig[inputConfig.Count];
 
@@ -78,11 +78,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             _device.Hid.Npads.Configure(npadConfig);
         }
 
-        internal void RefreshInputConfigEvent(object _, ReactiveEventArgs<List<InputConfig>> args)
-        {
-            RefreshInputConfig(args.NewValue);
-        }
-
         public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
         {
             const int stickButtonThreshold = short.MaxValue / 2;
diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs
index 69d461de24..e9582c2631 100644
--- a/Ryujinx.HLE/HOS/Services/IpcService.cs
+++ b/Ryujinx.HLE/HOS/Services/IpcService.cs
@@ -109,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Services
 
             bool serviceExists = service.HipcCommands.TryGetValue(commandId, out MethodInfo processRequest);
 
-            if (ServiceConfiguration.IgnoreMissingServices || serviceExists)
+            if (context.Device.Configuration.IgnoreMissingServices || serviceExists)
             {
                 ResultCode result = ResultCode.Success;
 
@@ -163,7 +163,7 @@ namespace Ryujinx.HLE.HOS.Services
 
             bool serviceExists = TipcCommands.TryGetValue(commandId, out MethodInfo processRequest);
 
-            if (ServiceConfiguration.IgnoreMissingServices || serviceExists)
+            if (context.Device.Configuration.IgnoreMissingServices || serviceExists)
             {
                 ResultCode result = ResultCode.Success;
 
diff --git a/Ryujinx.HLE/HOS/Services/ServiceConfiguration.cs b/Ryujinx.HLE/HOS/Services/ServiceConfiguration.cs
deleted file mode 100644
index d73c76d9cf..0000000000
--- a/Ryujinx.HLE/HOS/Services/ServiceConfiguration.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services
-{
-    public static class ServiceConfiguration
-    {
-        public static bool IgnoreMissingServices { get; set; }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index 9a0ccbc35e..8b1ec5b81b 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
@@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
                 }
                 else
                 {
-                    if (ServiceConfiguration.IgnoreMissingServices)
+                    if (context.Device.Configuration.IgnoreMissingServices)
                     {
                         Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
                     }
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
index 556e6a3b51..9d8e526f58 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
@@ -1,6 +1,5 @@
 using Ryujinx.Common.Configuration;
 using Ryujinx.Common.Logging;
-using Ryujinx.Configuration;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Gpu;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
@@ -351,7 +350,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
             bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
             bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);
 
-            AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
+            AspectRatio aspectRatio = _device.Configuration.AspectRatio;
             bool        isStretched = aspectRatio == AspectRatio.Stretched;
 
             ImageCrop crop = new ImageCrop(
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
index b66ffc3f1b..963ea9fd74 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
@@ -5,7 +5,6 @@ using LibHac.Fs.Fsa;
 using LibHac.FsSystem;
 using LibHac.FsSystem.NcaUtils;
 using Ryujinx.Common.Logging;
-using Ryujinx.Configuration;
 using Ryujinx.HLE.Exceptions;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
@@ -47,10 +46,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
             InitializeLocationNameCache();
         }
 
-        public string SanityCheckDeviceLocationName()
+        public string SanityCheckDeviceLocationName(string locationName)
         {
-            string locationName = ConfigurationState.Instance.System.TimeZone;
-
             if (IsLocationNameValid(locationName))
             {
                 return locationName;
@@ -58,8 +55,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
 
             Logger.Warning?.Print(LogClass.ServiceTime, $"Invalid device TimeZone {locationName}, switching back to UTC");
 
-            ConfigurationState.Instance.System.TimeZone.Value = "UTC";
-
             return "UTC";
         }
 
@@ -69,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
 
             SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null);
 
-            string deviceLocationName = SanityCheckDeviceLocationName();
+            string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone);
 
             ResultCode result = GetTimeZoneBinary(deviceLocationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile);
 
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index b88bdbfe23..ee359ddaef 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -1,22 +1,14 @@
-using LibHac.FsSystem;
 using Ryujinx.Audio.Backends.CompatLayer;
 using Ryujinx.Audio.Integration;
-using Ryujinx.Common;
-using Ryujinx.Configuration;
-using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Gpu;
 using Ryujinx.Graphics.Host1x;
 using Ryujinx.Graphics.Nvdec;
 using Ryujinx.Graphics.Vic;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS;
-using Ryujinx.HLE.HOS.Services;
-using Ryujinx.HLE.HOS.Services.Account.Acc;
 using Ryujinx.HLE.HOS.Services.Apm;
 using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
-using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.Memory;
 using System;
 
@@ -24,69 +16,60 @@ namespace Ryujinx.HLE
 {
     public class Switch : IDisposable
     {
-        private MemoryConfiguration _memoryConfiguration;
+        public HLEConfiguration Configuration { get; }
 
-        public IHardwareDeviceDriver AudioDeviceDriver { get; private set; }
+        public IHardwareDeviceDriver AudioDeviceDriver { get; }
 
-        internal MemoryBlock Memory { get; private set; }
+        internal MemoryBlock Memory { get; }
 
-        public GpuContext Gpu { get; private set; }
+        public GpuContext Gpu { get; }
 
-        internal NvMemoryAllocator MemoryAllocator { get; private set; }
+        internal NvMemoryAllocator MemoryAllocator { get; }
 
         internal Host1xDevice Host1x { get; }
 
-        public VirtualFileSystem FileSystem { get; private set; }
+        public VirtualFileSystem FileSystem => Configuration.VirtualFileSystem;
 
-        public Horizon System { get; private set; }
+        public Horizon System { get; }
 
         public ApplicationLoader Application { get; }
 
-        public PerformanceStatistics Statistics { get; private set; }
+        public PerformanceStatistics Statistics { get; }
 
-        public UserChannelPersistence UserChannelPersistence { get; }
+        public Hid Hid { get; }
 
-        public Hid Hid { get; private set; }
+        public TamperMachine TamperMachine { get; }
 
-        public TamperMachine TamperMachine { get; private set; }
-
-        public IHostUiHandler UiHandler { get; set; }
+        public IHostUiHandler UiHandler { get; }
 
         public bool EnableDeviceVsync { get; set; } = true;
 
-        public Switch(
-            VirtualFileSystem fileSystem,
-            ContentManager contentManager,
-            AccountManager accountManager,
-            UserChannelPersistence userChannelPersistence,
-            IRenderer renderer,
-            IHardwareDeviceDriver audioDeviceDriver,
-            MemoryConfiguration memoryConfiguration)
+        public Switch(HLEConfiguration configuration)
         {
-            if (renderer == null)
+            if (configuration.GpuRenderer == null)
             {
-                throw new ArgumentNullException(nameof(renderer));
+                throw new ArgumentNullException(nameof(configuration.GpuRenderer));
             }
 
-            if (audioDeviceDriver == null)
+            if (configuration.AudioDeviceDriver == null)
             {
-                throw new ArgumentNullException(nameof(audioDeviceDriver));
+                throw new ArgumentNullException(nameof(configuration.AudioDeviceDriver));
             }
 
-            if (userChannelPersistence == null)
+            if (configuration.UserChannelPersistence== null)
             {
-                throw new ArgumentNullException(nameof(userChannelPersistence));
+                throw new ArgumentNullException(nameof(configuration.UserChannelPersistence));
             }
 
-            UserChannelPersistence = userChannelPersistence;
+            Configuration = configuration;
 
-            _memoryConfiguration = memoryConfiguration;
+            UiHandler = configuration.HostUiHandler;
 
-            AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(audioDeviceDriver);
+            AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(configuration.AudioDeviceDriver);
 
-            Memory = new MemoryBlock(memoryConfiguration.ToDramSize());
+            Memory = new MemoryBlock(configuration.MemoryConfiguration.ToDramSize());
 
-            Gpu = new GpuContext(renderer);
+            Gpu = new GpuContext(configuration.GpuRenderer);
 
             MemoryAllocator = new NvMemoryAllocator();
 
@@ -111,9 +94,7 @@ namespace Ryujinx.HLE
                 }
             };
 
-            FileSystem = fileSystem;
-
-            System = new Horizon(this, contentManager, accountManager, memoryConfiguration);
+            System = new Horizon(this);
             System.InitializeServices();
 
             Statistics = new PerformanceStatistics();
@@ -121,45 +102,30 @@ namespace Ryujinx.HLE
             Hid = new Hid(this, System.HidBaseAddress);
             Hid.InitDevices();
 
-            Application = new ApplicationLoader(this, fileSystem, contentManager);
+            Application = new ApplicationLoader(this);
 
             TamperMachine = new TamperMachine();
+
+            Initialize();
         }
 
-        public void Initialize()
+        private void Initialize()
         {
-            System.State.SetLanguage((SystemLanguage)ConfigurationState.Instance.System.Language.Value);
+            System.State.SetLanguage(Configuration.SystemLanguage);
 
-            System.State.SetRegion((RegionCode)ConfigurationState.Instance.System.Region.Value);
+            System.State.SetRegion(Configuration.Region);
 
-            EnableDeviceVsync = ConfigurationState.Instance.Graphics.EnableVsync;
+            EnableDeviceVsync = Configuration.EnableVsync;
 
-            System.State.DockedMode = ConfigurationState.Instance.System.EnableDockedMode;
+            System.State.DockedMode = Configuration.EnableDockedMode;
 
             System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
 
-            System.EnablePtc = ConfigurationState.Instance.System.EnablePtc;
+            System.EnablePtc = Configuration.EnablePtc;
 
-            System.FsIntegrityCheckLevel = GetIntegrityCheckLevel();
+            System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
 
-            System.GlobalAccessLogMode = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
-
-            ServiceConfiguration.IgnoreMissingServices = ConfigurationState.Instance.System.IgnoreMissingServices;
-            ConfigurationState.Instance.System.IgnoreMissingServices.Event += (object _, ReactiveEventArgs<bool> args) =>
-            {
-                ServiceConfiguration.IgnoreMissingServices = args.NewValue;
-            };
-
-            // Configure controllers
-            Hid.RefreshInputConfig(ConfigurationState.Instance.Hid.InputConfig.Value);
-            ConfigurationState.Instance.Hid.InputConfig.Event += Hid.RefreshInputConfigEvent;
-        }
-
-        public static IntegrityCheckLevel GetIntegrityCheckLevel()
-        {
-            return ConfigurationState.Instance.System.EnableFsIntegrityChecks
-                ? IntegrityCheckLevel.ErrorOnInvalid
-                : IntegrityCheckLevel.None;
+            System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
         }
 
         public void LoadCart(string exeFsDir, string romFsFile = null)
@@ -223,8 +189,6 @@ namespace Ryujinx.HLE
         {
             if (disposing)
             {
-                ConfigurationState.Instance.Hid.InputConfig.Event -= Hid.RefreshInputConfigEvent;
-
                 System.Dispose();
                 Host1x.Dispose();
                 AudioDeviceDriver.Dispose();
diff --git a/Ryujinx.Input/HLE/NpadManager.cs b/Ryujinx.Input/HLE/NpadManager.cs
index 033a7ac5c2..abb820b0e4 100644
--- a/Ryujinx.Input/HLE/NpadManager.cs
+++ b/Ryujinx.Input/HLE/NpadManager.cs
@@ -1,8 +1,6 @@
 using Ryujinx.Common.Configuration.Hid;
 using Ryujinx.Common.Configuration.Hid.Controller;
 using Ryujinx.Common.Configuration.Hid.Keyboard;
-using Ryujinx.Configuration;
-using Ryujinx.HLE.HOS;
 using Ryujinx.HLE.HOS.Services.Hid;
 using System;
 using System.Collections.Generic;
@@ -10,6 +8,7 @@ using System.Diagnostics;
 using System.Runtime.CompilerServices;
 
 using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
+using Switch = Ryujinx.HLE.Switch;
 
 namespace Ryujinx.Input.HLE
 {
@@ -31,30 +30,41 @@ namespace Ryujinx.Input.HLE
         private bool _isDisposed;
 
         private List<InputConfig> _inputConfig;
+        private bool _enableKeyboard;
+        private Switch _device;
 
         public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver)
         {
             _controllers = new NpadController[MaxControllers];
-            _cemuHookClient = new CemuHookClient();
+            _cemuHookClient = new CemuHookClient(this);
 
             _keyboardDriver = keyboardDriver;
             _gamepadDriver = gamepadDriver;
-            _inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value;
+            _inputConfig = new List<InputConfig>();
+            _enableKeyboard = false;
 
             _gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
             _gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
         }
 
+        private void RefreshInputConfigForHLE()
+        {
+            lock (_lock)
+            {
+                _device.Hid.RefreshInputConfig(_inputConfig);
+            }
+        }
+
         private void HandleOnGamepadDisconnected(string obj)
         {
             // Force input reload
-            ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value);
+            ReloadConfiguration(_inputConfig, _enableKeyboard);
         }
 
         private void HandleOnGamepadConnected(string id)
         {
             // Force input reload
-            ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value);
+            ReloadConfiguration(_inputConfig, _enableKeyboard);
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -83,7 +93,7 @@ namespace Ryujinx.Input.HLE
             }
         }
 
-        public void ReloadConfiguration(List<InputConfig> inputConfig)
+        public void ReloadConfiguration(List<InputConfig> inputConfig, bool enableKeyboard)
         {
             lock (_lock)
             {
@@ -110,10 +120,9 @@ namespace Ryujinx.Input.HLE
                 }
 
                 _inputConfig = inputConfig;
+                _enableKeyboard = enableKeyboard;
 
-                // Enforce an update of the property that will be updated by HLE.
-                // TODO: Move that in the input manager maybe?
-                ConfigurationState.Instance.Hid.InputConfig.Value = inputConfig;
+                _device.Hid.RefreshInputConfig(inputConfig);
             }
         }
 
@@ -133,7 +142,15 @@ namespace Ryujinx.Input.HLE
             }
         }
 
-        public void Update(Hid hleHid, TamperMachine tamperMachine)
+        public void Initialize(Switch device, List<InputConfig> inputConfig, bool enableKeyboard)
+        {
+            _device = device;
+            _device.Configuration.RefreshInputConfig = RefreshInputConfigForHLE;
+
+            ReloadConfiguration(inputConfig, enableKeyboard);
+        }
+
+        public void Update()
         {
             lock (_lock)
             {
@@ -159,11 +176,11 @@ namespace Ryujinx.Input.HLE
 
                         inputState = controller.GetHLEInputState();
 
-                        inputState.Buttons |= hleHid.UpdateStickButtons(inputState.LStick, inputState.RStick);
+                        inputState.Buttons |= _device.Hid.UpdateStickButtons(inputState.LStick, inputState.RStick);
 
                         motionState = controller.GetHLEMotionState();
 
-                        if (ConfigurationState.Instance.Hid.EnableKeyboard)
+                        if (_enableKeyboard)
                         {
                             hleKeyboardInput = controller.GetHLEKeyboardInput();
                         }
@@ -181,15 +198,23 @@ namespace Ryujinx.Input.HLE
                     hleMotionStates.Add(motionState);
                 }
 
-                hleHid.Npads.Update(hleInputStates);
-                hleHid.Npads.UpdateSixAxis(hleMotionStates);
+                _device.Hid.Npads.Update(hleInputStates);
+                _device.Hid.Npads.UpdateSixAxis(hleMotionStates);
 
                 if (hleKeyboardInput.HasValue)
                 {
-                    hleHid.Keyboard.Update(hleKeyboardInput.Value);
+                    _device.Hid.Keyboard.Update(hleKeyboardInput.Value);
                 }
 
-                tamperMachine.UpdateInput(hleInputStates);
+                _device.TamperMachine.UpdateInput(hleInputStates);
+            }
+        }
+
+        internal InputConfig GetPlayerInputConfigByIndex(int index)
+        {
+            lock (_lock)
+            {
+                return _inputConfig.Find(x => x.PlayerIndex == (Ryujinx.Common.Configuration.Hid.PlayerIndex)index);
             }
         }
 
diff --git a/Ryujinx.Input/Motion/CemuHook/Client.cs b/Ryujinx.Input/Motion/CemuHook/Client.cs
index 395bd0b3d3..214e23f0f9 100644
--- a/Ryujinx.Input/Motion/CemuHook/Client.cs
+++ b/Ryujinx.Input/Motion/CemuHook/Client.cs
@@ -4,7 +4,7 @@ using Ryujinx.Common.Configuration.Hid;
 using Ryujinx.Common.Configuration.Hid.Controller;
 using Ryujinx.Common.Configuration.Hid.Controller.Motion;
 using Ryujinx.Common.Logging;
-using Ryujinx.Configuration;
+using Ryujinx.Input.HLE;
 using Ryujinx.Input.Motion.CemuHook.Protocol;
 using System;
 using System.Collections.Generic;
@@ -29,12 +29,14 @@ namespace Ryujinx.Input.Motion.CemuHook
 
         private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues(typeof(PlayerIndex)).Length];
         private readonly long[] _clientRetryTimer  = new long[Enum.GetValues(typeof(PlayerIndex)).Length];
+        private NpadManager _npadManager;
 
-        public Client()
+        public Client(NpadManager npadManager)
         {
-            _hosts      = new Dictionary<int, IPEndPoint>();
-            _motionData = new Dictionary<int, Dictionary<int, MotionInput>>();
-            _clients    = new Dictionary<int, UdpClient>();
+            _npadManager = npadManager;
+            _hosts       = new Dictionary<int, IPEndPoint>();
+            _motionData  = new Dictionary<int, Dictionary<int, MotionInput>>();
+            _clients     = new Dictionary<int, UdpClient>();
 
             CloseClients();
         }
@@ -323,7 +325,7 @@ namespace Ryujinx.Input.Motion.CemuHook
 
                     ulong timestamp = inputData.MotionTimestamp;
 
-                    InputConfig config = ConfigurationState.Instance.Hid.InputConfig.Value.Find(x => x.PlayerIndex == (PlayerIndex)clientId);
+                    InputConfig config = _npadManager.GetPlayerInputConfigByIndex(clientId);
 
                     lock (_motionData)
                     {
diff --git a/Ryujinx.Common/Configuration/AudioBackend.cs b/Ryujinx/Configuration/AudioBackend.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/AudioBackend.cs
rename to Ryujinx/Configuration/AudioBackend.cs
diff --git a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs b/Ryujinx/Configuration/ConfigurationFileFormat.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
rename to Ryujinx/Configuration/ConfigurationFileFormat.cs
diff --git a/Ryujinx.Common/Configuration/ConfigurationState.cs b/Ryujinx/Configuration/ConfigurationState.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/ConfigurationState.cs
rename to Ryujinx/Configuration/ConfigurationState.cs
diff --git a/Ryujinx.Common/Configuration/LoggerModule.cs b/Ryujinx/Configuration/LoggerModule.cs
similarity index 99%
rename from Ryujinx.Common/Configuration/LoggerModule.cs
rename to Ryujinx/Configuration/LoggerModule.cs
index 20c0fb464d..44631ea085 100644
--- a/Ryujinx.Common/Configuration/LoggerModule.cs
+++ b/Ryujinx/Configuration/LoggerModule.cs
@@ -1,7 +1,6 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using System;
-using System.IO;
 
 namespace Ryujinx.Configuration
 {
diff --git a/Ryujinx.Common/Configuration/System/Language.cs b/Ryujinx/Configuration/System/Language.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/System/Language.cs
rename to Ryujinx/Configuration/System/Language.cs
diff --git a/Ryujinx.Common/Configuration/System/Region.cs b/Ryujinx/Configuration/System/Region.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/System/Region.cs
rename to Ryujinx/Configuration/System/Region.cs
diff --git a/Ryujinx.Common/Configuration/Ui/ColumnSort.cs b/Ryujinx/Configuration/Ui/ColumnSort.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/Ui/ColumnSort.cs
rename to Ryujinx/Configuration/Ui/ColumnSort.cs
diff --git a/Ryujinx.Common/Configuration/Ui/GuiColumns.cs b/Ryujinx/Configuration/Ui/GuiColumns.cs
similarity index 100%
rename from Ryujinx.Common/Configuration/Ui/GuiColumns.cs
rename to Ryujinx/Configuration/Ui/GuiColumns.cs
diff --git a/Ryujinx/Ui/Applet/GtkHostUiHandler.cs b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs
index d74ea3d596..c227ebd382 100644
--- a/Ryujinx/Ui/Applet/GtkHostUiHandler.cs
+++ b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs
@@ -131,7 +131,7 @@ namespace Ryujinx.Ui.Applet
 
         public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
         {
-            device.UserChannelPersistence.ExecuteProgram(kind, value);
+            device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
             ((MainWindow)_parent).RendererWidget?.Exit();
         }
 
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index a2a009927e..1eef7554f3 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -2,12 +2,14 @@ using ARMeilleure.Translation;
 using ARMeilleure.Translation.PTC;
 using Gtk;
 using LibHac.Common;
+using LibHac.FsSystem;
 using LibHac.Ns;
 using Ryujinx.Audio.Backends.Dummy;
 using Ryujinx.Audio.Backends.OpenAL;
 using Ryujinx.Audio.Backends.SDL2;
 using Ryujinx.Audio.Backends.SoundIo;
 using Ryujinx.Audio.Integration;
+using Ryujinx.Common;
 using Ryujinx.Common.Configuration;
 using Ryujinx.Common.Logging;
 using Ryujinx.Common.System;
@@ -18,6 +20,7 @@ using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.FileSystem.Content;
 using Ryujinx.HLE.HOS;
 using Ryujinx.HLE.HOS.Services.Account.Acc;
+using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.Input.GTK3;
 using Ryujinx.Input.HLE;
 using Ryujinx.Input.SDL2;
@@ -166,6 +169,10 @@ namespace Ryujinx.Ui
 
             RendererWidgetBase.StatusUpdatedEvent += Update_StatusBar;
 
+            ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
+            ConfigurationState.Instance.Graphics.AspectRatio.Event         += UpdateAspectRatioState;
+            ConfigurationState.Instance.System.EnableDockedMode.Event      += UpdateDockedModeState;
+
             if (ConfigurationState.Instance.Ui.StartFullscreen)
             {
                 _startFullScreen.Active = true;
@@ -236,6 +243,30 @@ namespace Ryujinx.Ui
             InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver());
         }
 
+        private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs<bool> args)
+        {
+            if (_emulationContext != null)
+            {
+                _emulationContext.Configuration.IgnoreMissingServices = args.NewValue;
+            }
+        }
+
+        private void UpdateAspectRatioState(object sender, ReactiveEventArgs<AspectRatio> args)
+        {
+            if (_emulationContext != null)
+            {
+                _emulationContext.Configuration.AspectRatio = args.NewValue;
+            }
+        }
+
+        private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
+        {
+            if (_emulationContext != null)
+            {
+                _emulationContext.System.ChangeDockedModeState(e.NewValue);
+            }
+        }
+
         private void WindowStateEvent_Changed(object o, WindowStateEventArgs args)
         {
             _fullScreen.Label = args.Event.NewWindowState.HasFlag(Gdk.WindowState.Fullscreen) ? "Exit Fullscreen" : "Enter Fullscreen";
@@ -380,19 +411,29 @@ namespace Ryujinx.Ui
                 ? HLE.MemoryConfiguration.MemoryConfiguration6GB
                 : HLE.MemoryConfiguration.MemoryConfiguration4GB;
 
-            _emulationContext = new HLE.Switch(
-                _virtualFileSystem,
-                _contentManager,
-                _accountManager,
-                _userChannelPersistence,
-                renderer,
-                deviceDriver,
-                memoryConfiguration)
-            {
-                UiHandler = _uiHandler
-            };
+            IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
 
-            _emulationContext.Initialize();
+            HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(_virtualFileSystem,
+                                                                          _contentManager,
+                                                                          _accountManager,
+                                                                          _userChannelPersistence,
+                                                                          renderer,
+                                                                          deviceDriver,
+                                                                          memoryConfiguration,
+                                                                          _uiHandler,
+                                                                          (SystemLanguage)ConfigurationState.Instance.System.Language.Value,
+                                                                          (RegionCode)ConfigurationState.Instance.System.Region.Value,
+                                                                          ConfigurationState.Instance.Graphics.EnableVsync,
+                                                                          ConfigurationState.Instance.System.EnableDockedMode,
+                                                                          ConfigurationState.Instance.System.EnablePtc,
+                                                                          fsIntegrityCheckLevel,
+                                                                          ConfigurationState.Instance.System.FsGlobalAccessLogMode,
+                                                                          ConfigurationState.Instance.System.SystemTimeOffset,
+                                                                          ConfigurationState.Instance.System.TimeZone,
+                                                                          ConfigurationState.Instance.System.IgnoreMissingServices,
+                                                                          ConfigurationState.Instance.Graphics.AspectRatio);
+
+            _emulationContext = new HLE.Switch(configuration);
         }
 
         private void SetupProgressUiHandlers()
diff --git a/Ryujinx/Ui/RendererWidgetBase.cs b/Ryujinx/Ui/RendererWidgetBase.cs
index 1e388747d2..00882ba0c2 100644
--- a/Ryujinx/Ui/RendererWidgetBase.cs
+++ b/Ryujinx/Ui/RendererWidgetBase.cs
@@ -73,8 +73,6 @@ namespace Ryujinx.Ui
             NpadManager = _inputManager.CreateNpadManager();
             _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
 
-            NpadManager.ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value.ToList());
-
             WaitEvent = new ManualResetEvent(false);
 
             _glLogLevel = glLogLevel;
@@ -300,6 +298,8 @@ namespace Ryujinx.Ui
             Device = device;
             Renderer = Device.Gpu.Renderer;
             Renderer?.Window.SetSize(_windowWidth, _windowHeight);
+
+            NpadManager.Initialize(device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
         }
 
         public void Render()
@@ -488,7 +488,7 @@ namespace Ryujinx.Ui
                 });
             }
 
-            NpadManager.Update(Device.Hid, Device.TamperMachine);
+            NpadManager.Update();
 
             if (_isFocused)
             {
diff --git a/Ryujinx/Ui/Windows/ControllerWindow.cs b/Ryujinx/Ui/Windows/ControllerWindow.cs
index 2732bdcbde..0a3deec11d 100644
--- a/Ryujinx/Ui/Windows/ControllerWindow.cs
+++ b/Ryujinx/Ui/Windows/ControllerWindow.cs
@@ -1143,7 +1143,7 @@ namespace Ryujinx.Ui.Windows
 
             if (_mainWindow.RendererWidget != null)
             {
-                _mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig);
+                _mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
             }
 
             // Atomically replace and signal input change.
diff --git a/Ryujinx/Ui/Windows/SettingsWindow.cs b/Ryujinx/Ui/Windows/SettingsWindow.cs
index 94afb24254..43fea4e2c1 100644
--- a/Ryujinx/Ui/Windows/SettingsWindow.cs
+++ b/Ryujinx/Ui/Windows/SettingsWindow.cs
@@ -263,7 +263,7 @@ namespace Ryujinx.Ui.Windows
             }
 
             _systemTimeZoneEntry.WidthChars = Math.Max(20, maxLocationLength + 1); // Ensure minimum Entry width
-            _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName();
+            _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(ConfigurationState.Instance.System.TimeZone);
 
             _systemTimeZoneCompletion.MatchFunc = TimeZoneMatchFunc;
 
@@ -462,7 +462,7 @@ namespace Ryujinx.Ui.Windows
         {
             if (!_validTzRegions.Contains(_systemTimeZoneEntry.Text))
             {
-                _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName();
+                _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(ConfigurationState.Instance.System.TimeZone);
             }
         }