diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 0cc4d1c68..5d1664a31 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -10,6 +10,8 @@ add_executable(citra-qt
     Info.plist
     aboutdialog.cpp
     aboutdialog.h
+    applets/mii_selector.cpp
+    applets/mii_selector.h
     applets/swkbd.cpp
     applets/swkbd.h
     bootmanager.cpp
diff --git a/src/citra_qt/applets/mii_selector.cpp b/src/citra_qt/applets/mii_selector.cpp
new file mode 100644
index 000000000..b51a33fb7
--- /dev/null
+++ b/src/citra_qt/applets/mii_selector.cpp
@@ -0,0 +1,118 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QComboBox>
+#include <QDialogButtonBox>
+#include <QMessageBox>
+#include <QString>
+#include <QVBoxLayout>
+#include "citra_qt/applets/mii_selector.h"
+#include "common/file_util.h"
+#include "common/string_util.h"
+#include "core/file_sys/archive_extsavedata.h"
+#include "core/file_sys/file_backend.h"
+#include "core/hle/service/ptm/ptm.h"
+
+/**
+ * Converts a UTF-16 text in a container to a UTF-8 std::string.
+ */
+template <typename T>
+std::string TextFromBuffer(const T& text) {
+    const auto text_end = std::find(text.begin(), text.end(), u'\0');
+    const std::size_t text_size = std::distance(text.begin(), text_end);
+    std::u16string buffer(text_size, 0);
+    std::transform(text.begin(), text_end, buffer.begin(), [](u16_le character) {
+        return static_cast<char16_t>(static_cast<u16>(character));
+    });
+    return Common::UTF16ToUTF8(buffer);
+}
+
+QtMiiSelectorDialog::QtMiiSelectorDialog(QWidget* parent, QtMiiSelector* mii_selector_)
+    : QDialog(parent), mii_selector(mii_selector_) {
+    using namespace Frontend;
+    const auto config = mii_selector->config;
+    layout = new QVBoxLayout;
+    combobox = new QComboBox;
+    buttons = new QDialogButtonBox;
+    // Initialize buttons
+    buttons->addButton(tr(MII_BUTTON_OKAY), QDialogButtonBox::ButtonRole::AcceptRole);
+    if (config.enable_cancel_button) {
+        buttons->addButton(tr(MII_BUTTON_CANCEL), QDialogButtonBox::ButtonRole::RejectRole);
+    }
+
+    setWindowTitle(config.title.empty() || config.title.at(0) == '\x0000'
+                       ? tr("Mii Selector")
+                       : QString::fromStdString(config.title));
+
+    miis.push_back(HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data);
+    combobox->addItem(tr("Standard Mii"));
+
+    std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)};
+    FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true);
+
+    auto archive_result = extdata_archive_factory.Open(Service::PTM::ptm_shared_extdata_id, 0);
+    if (archive_result.Succeeded()) {
+        auto archive = std::move(archive_result).Unwrap();
+
+        FileSys::Path file_path = "/CFL_DB.dat";
+        FileSys::Mode mode{};
+        mode.read_flag.Assign(1);
+
+        auto file_result = archive->OpenFile(file_path, mode);
+        if (file_result.Succeeded()) {
+            auto file = std::move(file_result).Unwrap();
+
+            u32 saved_miis_offset = 0x8;
+            // The Mii Maker has a 100 Mii limit on the 3ds
+            for (int i = 0; i < 100; ++i) {
+                HLE::Applets::MiiData mii;
+                std::array<u8, sizeof(mii)> mii_raw;
+                file->Read(saved_miis_offset, sizeof(mii), mii_raw.data());
+                std::memcpy(&mii, mii_raw.data(), sizeof(mii));
+                if (mii.mii_id != 0) {
+                    std::string name = TextFromBuffer(mii.mii_name);
+                    miis.push_back(mii);
+                    combobox->addItem(QString::fromStdString(name));
+                }
+                saved_miis_offset += sizeof(mii);
+            }
+        }
+    }
+
+    if (combobox->count() > static_cast<int>(config.initially_selected_mii_index)) {
+        combobox->setCurrentIndex(static_cast<int>(config.initially_selected_mii_index));
+    }
+
+    connect(buttons, &QDialogButtonBox::accepted, this, [this] { accept(); });
+    connect(buttons, &QDialogButtonBox::rejected, this, [this] {
+        return_code = 1;
+        accept();
+    });
+    layout->addWidget(combobox);
+    layout->addWidget(buttons);
+    setLayout(layout);
+}
+
+QtMiiSelector::QtMiiSelector(QWidget& parent_) : parent(parent_) {}
+
+void QtMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
+    MiiSelector::Setup(config);
+    QMetaObject::invokeMethod(this, "OpenDialog", Qt::BlockingQueuedConnection);
+}
+
+void QtMiiSelector::OpenDialog() {
+    QtMiiSelectorDialog dialog(&parent, this);
+    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+                          Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
+    dialog.setWindowModality(Qt::WindowModal);
+    dialog.exec();
+
+    const auto index = dialog.combobox->currentIndex();
+    LOG_INFO(Frontend, "Mii Selector dialog finished (return_code={}, index={})",
+             dialog.return_code, index);
+
+    const auto mii_data = dialog.miis.at(index);
+    Finalize(dialog.return_code,
+             dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{});
+}
diff --git a/src/citra_qt/applets/mii_selector.h b/src/citra_qt/applets/mii_selector.h
new file mode 100644
index 000000000..c3b6eabb2
--- /dev/null
+++ b/src/citra_qt/applets/mii_selector.h
@@ -0,0 +1,46 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <unordered_map>
+#include <QDialog>
+#include "core/frontend/applets/mii_selector.h"
+
+class QComboBox;
+class QDialogButtonBox;
+class QVBoxLayout;
+class QtMiiSelector;
+
+class QtMiiSelectorDialog final : public QDialog {
+    Q_OBJECT
+
+public:
+    QtMiiSelectorDialog(QWidget* parent, QtMiiSelector* mii_selector_);
+
+private:
+    QDialogButtonBox* buttons;
+    QComboBox* combobox;
+    QVBoxLayout* layout;
+    QtMiiSelector* mii_selector;
+    u32 return_code = 0;
+    std::vector<HLE::Applets::MiiData> miis;
+
+    friend class QtMiiSelector;
+};
+
+class QtMiiSelector final : public QObject, public Frontend::MiiSelector {
+    Q_OBJECT
+
+public:
+    explicit QtMiiSelector(QWidget& parent);
+    void Setup(const Frontend::MiiSelectorConfig& config) override;
+
+private:
+    Q_INVOKABLE void OpenDialog();
+
+    QWidget& parent;
+
+    friend class QtMiiSelectorDialog;
+};
diff --git a/src/citra_qt/applets/swkbd.cpp b/src/citra_qt/applets/swkbd.cpp
index a9237389a..7514524b3 100644
--- a/src/citra_qt/applets/swkbd.cpp
+++ b/src/citra_qt/applets/swkbd.cpp
@@ -25,7 +25,7 @@ QtKeyboardValidator::State QtKeyboardValidator::validate(QString& input, int& po
 QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
     : QDialog(parent), keyboard(keyboard_) {
     using namespace Frontend;
-    KeyboardConfig config = keyboard->config;
+    const auto config = keyboard->config;
     layout = new QVBoxLayout;
     label = new QLabel(QString::fromStdString(config.hint_text));
     line_edit = new QLineEdit;
@@ -36,31 +36,31 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
     case ButtonConfig::Triple:
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[2])
-                               : tr(BUTTON_OKAY),
+                               : tr(SWKBD_BUTTON_OKAY),
                            QDialogButtonBox::ButtonRole::AcceptRole);
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[1])
-                               : tr(BUTTON_FORGOT),
+                               : tr(SWKBD_BUTTON_FORGOT),
                            QDialogButtonBox::ButtonRole::HelpRole);
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[0])
-                               : tr(BUTTON_CANCEL),
+                               : tr(SWKBD_BUTTON_CANCEL),
                            QDialogButtonBox::ButtonRole::RejectRole);
         break;
     case ButtonConfig::Dual:
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[1])
-                               : tr(BUTTON_OKAY),
+                               : tr(SWKBD_BUTTON_OKAY),
                            QDialogButtonBox::ButtonRole::AcceptRole);
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[0])
-                               : tr(BUTTON_CANCEL),
+                               : tr(SWKBD_BUTTON_CANCEL),
                            QDialogButtonBox::ButtonRole::RejectRole);
         break;
     case ButtonConfig::Single:
         buttons->addButton(config.has_custom_button_text
                                ? QString::fromStdString(config.button_text[0])
-                               : tr(BUTTON_OKAY),
+                               : tr(SWKBD_BUTTON_OKAY),
                            QDialogButtonBox::ButtonRole::AcceptRole);
         break;
     case ButtonConfig::None:
@@ -109,7 +109,7 @@ void QtKeyboardDialog::HandleValidationError(Frontend::ValidationError error) {
 
 QtKeyboard::QtKeyboard(QWidget& parent_) : parent(parent_) {}
 
-void QtKeyboard::Setup(const Frontend::KeyboardConfig* config) {
+void QtKeyboard::Setup(const Frontend::KeyboardConfig& config) {
     SoftwareKeyboard::Setup(config);
     if (this->config.button_config != Frontend::ButtonConfig::None) {
         ok_id = static_cast<u8>(this->config.button_config);
diff --git a/src/citra_qt/applets/swkbd.h b/src/citra_qt/applets/swkbd.h
index cfcbcb45e..5fcbd7112 100644
--- a/src/citra_qt/applets/swkbd.h
+++ b/src/citra_qt/applets/swkbd.h
@@ -48,7 +48,7 @@ class QtKeyboard final : public QObject, public Frontend::SoftwareKeyboard {
 
 public:
     explicit QtKeyboard(QWidget& parent);
-    void Setup(const Frontend::KeyboardConfig* config) override;
+    void Setup(const Frontend::KeyboardConfig& config) override;
 
 private:
     Q_INVOKABLE void OpenInputDialog();
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index d0a3a3720..f3d1d6582 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -16,6 +16,7 @@
 #include <QtWidgets>
 #include <fmt/format.h>
 #include "citra_qt/aboutdialog.h"
+#include "citra_qt/applets/mii_selector.h"
 #include "citra_qt/applets/swkbd.h"
 #include "citra_qt/bootmanager.h"
 #include "citra_qt/camera/qt_multimedia_camera.h"
@@ -1896,7 +1897,8 @@ int main(int argc, char* argv[]) {
 
     // Register frontend applets
     Frontend::RegisterDefaultApplets();
-    Frontend::RegisterSoftwareKeyboard(std::make_shared<QtKeyboard>(main_window));
+    Core::System::GetInstance().RegisterMiiSelector(std::make_shared<QtMiiSelector>(main_window));
+    Core::System::GetInstance().RegisterSoftwareKeyboard(std::make_shared<QtKeyboard>(main_window));
 
     main_window.show();
     int result = app.exec();
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b70ef57be..633c9296b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -84,6 +84,8 @@ add_library(core STATIC
     file_sys/title_metadata.h
     frontend/applets/default_applets.cpp
     frontend/applets/default_applets.h
+    frontend/applets/mii_selector.cpp
+    frontend/applets/mii_selector.h
     frontend/applets/swkbd.cpp
     frontend/applets/swkbd.h
     frontend/camera/blank_camera.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index a72c8a1e9..2696118e2 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -276,6 +276,10 @@ const Cheats::CheatEngine& System::CheatEngine() const {
     return *cheat_engine;
 }
 
+void System::RegisterMiiSelector(std::shared_ptr<Frontend::MiiSelector> mii_selector) {
+    registered_mii_selector = std::move(mii_selector);
+}
+
 void System::RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd) {
     registered_swkbd = std::move(swkbd);
 }
diff --git a/src/core/core.h b/src/core/core.h
index 2e0c9ce7f..44e6ea796 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 #include "common/common_types.h"
+#include "core/frontend/applets/mii_selector.h"
 #include "core/frontend/applets/swkbd.h"
 #include "core/loader/loader.h"
 #include "core/memory.h"
@@ -222,8 +223,14 @@ public:
 
     /// Frontend Applets
 
+    void RegisterMiiSelector(std::shared_ptr<Frontend::MiiSelector> mii_selector);
+
     void RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd);
 
+    std::shared_ptr<Frontend::MiiSelector> GetMiiSelector() const {
+        return registered_mii_selector;
+    }
+
     std::shared_ptr<Frontend::SoftwareKeyboard> GetSoftwareKeyboard() const {
         return registered_swkbd;
     }
@@ -260,6 +267,7 @@ private:
     std::shared_ptr<Service::SM::ServiceManager> service_manager;
 
     /// Frontend applets
+    std::shared_ptr<Frontend::MiiSelector> registered_mii_selector;
     std::shared_ptr<Frontend::SoftwareKeyboard> registered_swkbd;
 
     /// Cheats manager
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 259ece84a..2df4f98c4 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -40,6 +40,9 @@ public:
     Path() : type(LowPathType::Invalid) {}
     Path(const char* path) : type(LowPathType::Char), string(path) {}
     Path(std::vector<u8> binary_data) : type(LowPathType::Binary), binary(std::move(binary_data)) {}
+    template <std::size_t size>
+    Path(const std::array<u8, size>& binary_data)
+        : type(LowPathType::Binary), binary(binary_data.begin(), binary_data.end()) {}
     Path(LowPathType type, const std::vector<u8>& data);
 
     LowPathType GetType() const {
diff --git a/src/core/frontend/applets/default_applets.cpp b/src/core/frontend/applets/default_applets.cpp
index 814b6381e..38a6c48dd 100644
--- a/src/core/frontend/applets/default_applets.cpp
+++ b/src/core/frontend/applets/default_applets.cpp
@@ -2,11 +2,14 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "core/core.h"
 #include "core/frontend/applets/default_applets.h"
+#include "core/frontend/applets/mii_selector.h"
 #include "core/frontend/applets/swkbd.h"
 
 namespace Frontend {
 void RegisterDefaultApplets() {
-    RegisterSoftwareKeyboard(std::make_shared<DefaultKeyboard>());
+    Core::System::GetInstance().RegisterSoftwareKeyboard(std::make_shared<DefaultKeyboard>());
+    Core::System::GetInstance().RegisterMiiSelector(std::make_shared<DefaultMiiSelector>());
 }
 } // namespace Frontend
diff --git a/src/core/frontend/applets/mii_selector.cpp b/src/core/frontend/applets/mii_selector.cpp
new file mode 100644
index 000000000..2ca23f1db
--- /dev/null
+++ b/src/core/frontend/applets/mii_selector.cpp
@@ -0,0 +1,18 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/frontend/applets/mii_selector.h"
+
+namespace Frontend {
+
+void MiiSelector::Finalize(u32 return_code, HLE::Applets::MiiData mii) {
+    data = {return_code, mii};
+}
+
+void DefaultMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
+    MiiSelector::Setup(config);
+    Finalize(0, HLE::Applets::MiiSelector::GetStandardMiiResult().selected_mii_data);
+}
+
+} // namespace Frontend
diff --git a/src/core/frontend/applets/mii_selector.h b/src/core/frontend/applets/mii_selector.h
new file mode 100644
index 000000000..588bc0c5b
--- /dev/null
+++ b/src/core/frontend/applets/mii_selector.h
@@ -0,0 +1,56 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include "core/hle/applets/mii_selector.h"
+
+namespace Frontend {
+
+/// Default English button text mappings. Frontends may need to copy this to internationalize it.
+constexpr char MII_BUTTON_OKAY[] = "Ok";
+constexpr char MII_BUTTON_CANCEL[] = "Cancel";
+
+/// Configuration that's relevant to frontend implementation of applet. Anything missing that we
+/// later learn is needed can be added here and filled in by the backend HLE applet
+struct MiiSelectorConfig {
+    bool enable_cancel_button;
+    std::string title;
+    u32 initially_selected_mii_index;
+};
+
+struct MiiSelectorData {
+    u32 return_code;
+    HLE::Applets::MiiData mii;
+};
+
+class MiiSelector {
+public:
+    virtual void Setup(const MiiSelectorConfig& config) {
+        this->config = MiiSelectorConfig(config);
+    }
+
+    const MiiSelectorData& ReceiveData() const {
+        return data;
+    }
+
+    /**
+     * Stores the data so that the HLE applet in core can
+     * send this to the calling application
+     */
+    void Finalize(u32 return_code, HLE::Applets::MiiData mii);
+
+protected:
+    MiiSelectorConfig config;
+    MiiSelectorData data;
+};
+
+class DefaultMiiSelector final : public MiiSelector {
+public:
+    void Setup(const MiiSelectorConfig& config) override;
+};
+
+} // namespace Frontend
diff --git a/src/core/frontend/applets/swkbd.cpp b/src/core/frontend/applets/swkbd.cpp
index 6c7442913..d1513e20c 100644
--- a/src/core/frontend/applets/swkbd.cpp
+++ b/src/core/frontend/applets/swkbd.cpp
@@ -135,7 +135,7 @@ ValidationError SoftwareKeyboard::Finalize(const std::string& text, u8 button) {
     return ValidationError::None;
 }
 
-void DefaultKeyboard::Setup(const Frontend::KeyboardConfig* config) {
+void DefaultKeyboard::Setup(const Frontend::KeyboardConfig& config) {
     SoftwareKeyboard::Setup(config);
 
     auto cfg = Service::CFG::GetModule(Core::System::GetInstance());
@@ -157,12 +157,4 @@ void DefaultKeyboard::Setup(const Frontend::KeyboardConfig* config) {
     }
 }
 
-void RegisterSoftwareKeyboard(std::shared_ptr<SoftwareKeyboard> applet) {
-    Core::System::GetInstance().RegisterSoftwareKeyboard(applet);
-}
-
-std::shared_ptr<SoftwareKeyboard> GetRegisteredSoftwareKeyboard() {
-    return Core::System::GetInstance().GetSoftwareKeyboard();
-}
-
 } // namespace Frontend
diff --git a/src/core/frontend/applets/swkbd.h b/src/core/frontend/applets/swkbd.h
index 5c07eb12d..f678c0f48 100644
--- a/src/core/frontend/applets/swkbd.h
+++ b/src/core/frontend/applets/swkbd.h
@@ -30,9 +30,9 @@ enum class ButtonConfig {
 };
 
 /// Default English button text mappings. Frontends may need to copy this to internationalize it.
-constexpr char BUTTON_OKAY[] = "Ok";
-constexpr char BUTTON_CANCEL[] = "Cancel";
-constexpr char BUTTON_FORGOT[] = "I Forgot";
+constexpr char SWKBD_BUTTON_OKAY[] = "Ok";
+constexpr char SWKBD_BUTTON_CANCEL[] = "Cancel";
+constexpr char SWKBD_BUTTON_FORGOT[] = "I Forgot";
 
 /// Configuration thats relevent to frontend implementation of applets. Anything missing that we
 /// later learn is needed can be added here and filled in by the backend HLE applet
@@ -82,11 +82,12 @@ enum class ValidationError {
 
 class SoftwareKeyboard {
 public:
-    virtual void Setup(const KeyboardConfig* config) {
-        this->config = KeyboardConfig(*config);
+    virtual void Setup(const KeyboardConfig& config) {
+        this->config = KeyboardConfig(config);
     }
-    const KeyboardData* ReceiveData() {
-        return &data;
+
+    const KeyboardData& ReceiveData() const {
+        return data;
     }
 
     /**
@@ -121,11 +122,7 @@ protected:
 
 class DefaultKeyboard final : public SoftwareKeyboard {
 public:
-    void Setup(const KeyboardConfig* config) override;
+    void Setup(const KeyboardConfig& config) override;
 };
 
-void RegisterSoftwareKeyboard(std::shared_ptr<SoftwareKeyboard> applet);
-
-std::shared_ptr<SoftwareKeyboard> GetRegisteredSoftwareKeyboard();
-
 } // namespace Frontend
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index 58311902d..596e216c0 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -4,10 +4,12 @@
 
 #include <cstring>
 #include <string>
+#include <boost/crc.hpp>
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/string_util.h"
 #include "core/core.h"
+#include "core/frontend/applets/mii_selector.h"
 #include "core/hle/applets/mii_selector.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/shared_memory.h"
@@ -17,6 +19,20 @@
 
 namespace HLE::Applets {
 
+/**
+ * Converts a UTF-16 text in a container to a UTF-8 std::string.
+ */
+template <typename T>
+std::string TextFromBuffer(const T& text) {
+    const auto text_end = std::find(text.begin(), text.end(), u'\0');
+    const std::size_t text_size = std::distance(text.begin(), text_end);
+    std::u16string buffer(text_size, 0);
+    std::transform(text.begin(), text_end, buffer.begin(), [](u16_le character) {
+        return static_cast<char16_t>(static_cast<u16>(character));
+    });
+    return Common::UTF16ToUTF8(buffer);
+}
+
 ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) {
     if (parameter.signal != Service::APT::SignalType::Request) {
         LOG_ERROR(Service_APT, "unsupported signal {}", static_cast<u32>(parameter.signal));
@@ -52,12 +68,51 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
 }
 
 ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
-    is_running = true;
-
-    // TODO(Subv): Reverse the parameter format for the Mii Selector
+    ASSERT_MSG(parameter.buffer.size() == sizeof(config),
+               "The size of the parameter (MiiConfig) is wrong");
 
     memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
 
+    using namespace Frontend;
+    frontend_applet = Core::System::GetInstance().GetMiiSelector();
+    ASSERT(frontend_applet);
+
+    MiiSelectorConfig frontend_config = ToFrontendConfig(config);
+    frontend_applet->Setup(frontend_config);
+
+    is_running = true;
+    return RESULT_SUCCESS;
+}
+
+void MiiSelector::Update() {
+    using namespace Frontend;
+    const MiiSelectorData& data = frontend_applet->ReceiveData();
+    result.return_code = data.return_code;
+    result.selected_mii_data = data.mii;
+    // Calculate the checksum of the selected Mii, see https://www.3dbrew.org/wiki/Mii#Checksum
+    result.mii_data_checksum = boost::crc<16, 0x1021, 0, 0, false, false>(
+        &result.selected_mii_data, sizeof(HLE::Applets::MiiData) + sizeof(result.unknown1));
+    result.selected_guest_mii_index = 0xFFFFFFFF;
+
+    // TODO(Subv): We're finalizing the applet immediately after it's started,
+    // but we should defer this call until after all the input has been collected.
+    Finalize();
+}
+
+void MiiSelector::Finalize() {
+    // Let the application know that we're closing
+    Service::APT::MessageParameter message;
+    message.buffer.resize(sizeof(MiiResult));
+    std::memcpy(message.buffer.data(), &result, message.buffer.size());
+    message.signal = Service::APT::SignalType::WakeupByExit;
+    message.destination_id = Service::APT::AppletId::Application;
+    message.sender_id = id;
+    SendParameter(message);
+
+    is_running = false;
+}
+
+MiiResult MiiSelector::GetStandardMiiResult() {
     // This data was obtained by writing the returned buffer in AppletManager::GlanceParameter of
     // the LLEd Mii picker of version system version 11.8.0 to a file and then matching the values
     // to the members of the MiiResult struct
@@ -95,18 +150,14 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
     result.mii_data_checksum = 0x056C;
     result.guest_mii_name.fill(0x0);
 
-    // Let the application know that we're closing
-    Service::APT::MessageParameter message;
-    message.buffer.resize(sizeof(MiiResult));
-    std::memcpy(message.buffer.data(), &result, message.buffer.size());
-    message.signal = Service::APT::SignalType::WakeupByExit;
-    message.destination_id = Service::APT::AppletId::Application;
-    message.sender_id = id;
-    SendParameter(message);
-
-    is_running = false;
-    return RESULT_SUCCESS;
+    return result;
 }
 
-void MiiSelector::Update() {}
+Frontend::MiiSelectorConfig MiiSelector::ToFrontendConfig(const MiiConfig& config) const {
+    Frontend::MiiSelectorConfig frontend_config;
+    frontend_config.enable_cancel_button = config.enable_cancel_button == 1;
+    frontend_config.title = TextFromBuffer(config.title);
+    frontend_config.initially_selected_mii_index = config.initially_selected_mii_index;
+    return frontend_config;
+}
 } // namespace HLE::Applets
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h
index c4a7dae19..0a8b8113c 100644
--- a/src/core/hle/applets/mii_selector.h
+++ b/src/core/hle/applets/mii_selector.h
@@ -12,6 +12,11 @@
 #include "core/hle/result.h"
 #include "core/hle/service/apt/apt.h"
 
+namespace Frontend {
+class MiiSelector;
+struct MiiSelectorConfig;
+} // namespace Frontend
+
 namespace HLE::Applets {
 
 struct MiiConfig {
@@ -19,13 +24,13 @@ struct MiiConfig {
     u8 enable_guest_mii;
     u8 show_on_top_screen;
     INSERT_PADDING_BYTES(5);
-    u16 title[0x40];
+    std::array<u16_le, 0x40> title;
     INSERT_PADDING_BYTES(4);
     u8 show_guest_miis;
     INSERT_PADDING_BYTES(3);
     u32 initially_selected_mii_index;
-    u8 guest_mii_whitelist[6];
-    u8 user_mii_whitelist[0x64];
+    std::array<u8, 0x6> guest_mii_whitelist;
+    std::array<u8, 0x64> user_mii_whitelist;
     INSERT_PADDING_BYTES(2);
     u32 magic_value;
 };
@@ -117,12 +122,26 @@ public:
     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
     void Update() override;
 
+    /**
+     * Sends the LibAppletClosing signal to the application,
+     * along with the relevant data buffers.
+     */
+    void Finalize();
+
+    static MiiResult GetStandardMiiResult();
+
 private:
+    Frontend::MiiSelectorConfig ToFrontendConfig(const MiiConfig& config) const;
+
     /// This SharedMemory will be created when we receive the LibAppJustStarted message.
     /// It holds the framebuffer info retrieved by the application with
     /// GSPGPU::ImportDisplayCaptureInfo
     std::shared_ptr<Kernel::SharedMemory> framebuffer_memory;
 
     MiiConfig config;
+
+    MiiResult result{};
+
+    std::shared_ptr<Frontend::MiiSelector> frontend_applet;
 };
 } // namespace HLE::Applets
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 3f209e9f4..4e4dd1b90 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -68,11 +68,11 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons
     DrawScreenKeyboard();
 
     using namespace Frontend;
-    frontend_applet = GetRegisteredSoftwareKeyboard();
-    if (frontend_applet) {
-        KeyboardConfig frontend_config = ToFrontendConfig(config);
-        frontend_applet->Setup(&frontend_config);
-    }
+    frontend_applet = Core::System::GetInstance().GetSoftwareKeyboard();
+    ASSERT(frontend_applet);
+
+    KeyboardConfig frontend_config = ToFrontendConfig(config);
+    frontend_applet->Setup(frontend_config);
 
     is_running = true;
     return RESULT_SUCCESS;
@@ -80,7 +80,7 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons
 
 void SoftwareKeyboard::Update() {
     using namespace Frontend;
-    KeyboardData data(*frontend_applet->ReceiveData());
+    KeyboardData data(frontend_applet->ReceiveData());
     std::u16string text = Common::UTF8ToUTF16(data.text);
     memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
     switch (config.num_buttons_m1) {
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 9ba14d407..f86ce78dc 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -23,9 +23,6 @@ namespace Service::PTM {
 /// Values for the default gamecoin.dat file
 static const GameCoin default_game_coin = {0x4F00, 42, 0, 0, 0, 2014, 12, 29};
 
-/// Id of the SharedExtData archive used by the PTM process
-static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
-
 void Module::Interface::GetAdapterState(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x5, 0, 0);
 
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index e56a66972..549e69353 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -15,6 +15,9 @@ class System;
 
 namespace Service::PTM {
 
+/// Id of the SharedExtData archive used by the PTM process
+constexpr std::array<u8, 12> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
+
 /// Charge levels used by PTM functions
 enum class ChargeLevels : u32 {
     CriticalBattery = 1,