diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 662030782..89578024f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -135,7 +135,8 @@ set(SRCS
             hle/service/nim/nim_aoc.cpp
             hle/service/nim/nim_s.cpp
             hle/service/nim/nim_u.cpp
-            hle/service/ns_s.cpp
+            hle/service/ns/ns.cpp
+            hle/service/ns/ns_s.cpp
             hle/service/nwm/nwm.cpp
             hle/service/nwm/nwm_cec.cpp
             hle/service/nwm/nwm_ext.cpp
@@ -334,7 +335,8 @@ set(HEADERS
             hle/service/nim/nim_aoc.h
             hle/service/nim/nim_s.h
             hle/service/nim/nim_u.h
-            hle/service/ns_s.h
+            hle/service/ns/ns.h
+            hle/service/ns/ns_s.h
             hle/service/nwm/nwm.h
             hle/service/nwm/nwm_cec.h
             hle/service/nwm/nwm_ext.h
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
new file mode 100644
index 000000000..9e19c38bf
--- /dev/null
+++ b/src/core/hle/service/ns/ns.cpp
@@ -0,0 +1,16 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ns/ns.h"
+#include "core/hle/service/ns/ns_s.h"
+
+namespace Service {
+namespace NS {
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+    std::make_shared<NS_S>()->InstallAsService(service_manager);
+}
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
new file mode 100644
index 000000000..c3d67d98c
--- /dev/null
+++ b/src/core/hle/service/ns/ns.h
@@ -0,0 +1,16 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NS {
+
+/// Registers all NS services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/ns_s.cpp b/src/core/hle/service/ns/ns_s.cpp
new file mode 100644
index 000000000..d952888dc
--- /dev/null
+++ b/src/core/hle/service/ns/ns_s.cpp
@@ -0,0 +1,34 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ns/ns_s.h"
+
+namespace Service {
+namespace NS {
+
+NS_S::NS_S() : ServiceFramework("ns:s", 2) {
+    static const FunctionInfo functions[] = {
+        {0x000100C0, nullptr, "LaunchFIRM"},
+        {0x000200C0, nullptr, "LaunchTitle"},
+        {0x00030000, nullptr, "TerminateApplication"},
+        {0x00040040, nullptr, "TerminateProcess"},
+        {0x000500C0, nullptr, "LaunchApplicationFIRM"},
+        {0x00060042, nullptr, "SetFIRMParams4A0"},
+        {0x00070042, nullptr, "CardUpdateInitialize"},
+        {0x00080000, nullptr, "CardUpdateShutdown"},
+        {0x000D0140, nullptr, "SetTWLBannerHMAC"},
+        {0x000E0000, nullptr, "ShutdownAsync"},
+        {0x00100180, nullptr, "RebootSystem"},
+        {0x00110100, nullptr, "TerminateTitle"},
+        {0x001200C0, nullptr, "SetApplicationCpuTimeLimit"},
+        {0x00150140, nullptr, "LaunchApplication"},
+        {0x00160000, nullptr, "RebootSystemClean"},
+    };
+    RegisterHandlers(functions);
+}
+
+NS_S::~NS_S() = default;
+
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns_s.h b/src/core/hle/service/ns/ns_s.h
similarity index 68%
rename from src/core/hle/service/ns_s.h
rename to src/core/hle/service/ns/ns_s.h
index 90288a521..660ae453f 100644
--- a/src/core/hle/service/ns_s.h
+++ b/src/core/hle/service/ns/ns_s.h
@@ -4,18 +4,17 @@
 
 #pragma once
 
+#include "core/hle/kernel/kernel.h"
 #include "core/hle/service/service.h"
 
 namespace Service {
 namespace NS {
 
-class NS_S final : public Interface {
+/// Interface to "ns:s" service
+class NS_S final : public ServiceFramework<NS_S> {
 public:
     NS_S();
-
-    std::string GetPortName() const override {
-        return "ns:s";
-    }
+    ~NS_S();
 };
 
 } // namespace NS
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
deleted file mode 100644
index 215c9aacc..000000000
--- a/src/core/hle/service/ns_s.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/service/ns_s.h"
-
-namespace Service {
-namespace NS {
-
-const Interface::FunctionInfo FunctionTable[] = {
-    {0x000100C0, nullptr, "LaunchFIRM"},
-    {0x000200C0, nullptr, "LaunchTitle"},
-    {0x00030000, nullptr, "TerminateApplication"},
-    {0x00040040, nullptr, "TerminateProcess"},
-    {0x000500C0, nullptr, "LaunchApplicationFIRM"},
-    {0x00060042, nullptr, "SetFIRMParams4A0"},
-    {0x00070042, nullptr, "CardUpdateInitialize"},
-    {0x00080000, nullptr, "CardUpdateShutdown"},
-    {0x000D0140, nullptr, "SetTWLBannerHMAC"},
-    {0x000E0000, nullptr, "ShutdownAsync"},
-    {0x00100180, nullptr, "RebootSystem"},
-    {0x00110100, nullptr, "TerminateTitle"},
-    {0x001200C0, nullptr, "SetApplicationCpuTimeLimit"},
-    {0x00150140, nullptr, "LaunchApplication"},
-    {0x00160000, nullptr, "RebootSystemClean"},
-};
-
-NS_S::NS_S() {
-    Register(FunctionTable);
-}
-
-} // namespace NS
-} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index aad950e50..f267aad74 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -38,7 +38,7 @@
 #include "core/hle/service/news/news.h"
 #include "core/hle/service/nfc/nfc.h"
 #include "core/hle/service/nim/nim.h"
-#include "core/hle/service/ns_s.h"
+#include "core/hle/service/ns/ns.h"
 #include "core/hle/service/nwm/nwm.h"
 #include "core/hle/service/pm_app.h"
 #include "core/hle/service/ptm/ptm.h"
@@ -215,6 +215,8 @@ void Init() {
     SM::g_service_manager = std::make_shared<SM::ServiceManager>();
     SM::ServiceManager::InstallInterfaces(SM::g_service_manager);
 
+    NS::InstallInterfaces(*SM::g_service_manager);
+
     AddNamedPort(new ERR::ERR_F);
 
     FS::ArchiveInit();
@@ -246,7 +248,6 @@ void Init() {
     AddService(new HTTP::HTTP_C);
     AddService(new LDR::LDR_RO);
     AddService(new MIC::MIC_U);
-    AddService(new NS::NS_S);
     AddService(new PM::PM_APP);
     AddService(new SOC::SOC_U);
     AddService(new SSL::SSL_C);