diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d92a46b00..fd14af1e7 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -32,6 +32,9 @@
 
 namespace Service::AM {
 
+constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
+constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
+
 enum class AppletId : u32 {
     SoftwareKeyboard = 0x11,
 };
@@ -529,7 +532,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
 class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
 public:
     explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
-        : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
+        : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)),
+          broker(std::make_shared<Applets::AppletDataBroker>()) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
@@ -554,34 +558,16 @@ public:
         // clang-format on
 
         RegisterHandlers(functions);
-
-        auto& kernel = Core::System::GetInstance().Kernel();
-        state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
-                                                    "ILibraryAppletAccessor:StateChangedEvent");
-        pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
-                                                   "ILibraryAppletAccessor:PopDataOutEvent");
-        pop_interactive_out_data_event =
-            Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
-                                  "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
     }
 
 private:
-    void AppletStorageProxyOutData(IStorage storage) {
-        storage_stack.push(std::make_shared<IStorage>(storage));
-        pop_out_data_event->Signal();
-    }
-
-    void AppletStorageProxyOutInteractiveData(IStorage storage) {
-        interactive_storage_stack.push(std::make_shared<IStorage>(storage));
-        pop_interactive_out_data_event->Signal();
-    }
-
     void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
-        state_changed_event->Signal();
+        const auto event = broker->GetStateChangedEvent();
+        event->Signal();
 
         IPC::ResponseBuilder rb{ctx, 2, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushCopyObjects(state_changed_event);
+        rb.PushCopyObjects(event);
 
         LOG_DEBUG(Service_AM, "called");
     }
@@ -604,14 +590,8 @@ private:
     void Start(Kernel::HLERequestContext& ctx) {
         ASSERT(applet != nullptr);
 
-        applet->Initialize(storage_stack);
-        while (!storage_stack.empty())
-            storage_stack.pop();
-        while (!interactive_storage_stack.empty())
-            interactive_storage_stack.pop();
-        applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); },
-                        [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); },
-                        [this] { state_changed_event->Signal(); });
+        applet->Initialize(broker);
+        applet->Execute();
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
@@ -621,7 +601,7 @@ private:
 
     void PushInData(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
-        storage_stack.push(rp.PopIpcInterface<IStorage>());
+        broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
@@ -632,28 +612,25 @@ private:
     void PopOutData(Kernel::HLERequestContext& ctx) {
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
 
-        if (storage_stack.empty()) {
-            rb.Push(ResultCode(-1));
+        const auto storage = broker->PopNormalDataToGame();
+        if (storage == nullptr) {
+            rb.Push(ERR_NO_DATA_IN_CHANNEL);
             return;
         }
 
         rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<IStorage>(std::move(storage_stack.front()));
-
-        storage_stack.pop();
+        rb.PushIpcInterface<IStorage>(std::move(*storage));
 
         LOG_DEBUG(Service_AM, "called");
     }
 
     void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
-        interactive_storage_stack.push(rp.PopIpcInterface<IStorage>());
+        broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
 
         ASSERT(applet->IsInitialized());
-        applet->ReceiveInteractiveData(interactive_storage_stack.back());
-        applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); },
-                        [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); },
-                        [this] { state_changed_event->Signal(); });
+        applet->ExecuteInteractive();
+        applet->Execute();
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
@@ -664,15 +641,14 @@ private:
     void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
 
-        if (interactive_storage_stack.empty()) {
-            rb.Push(ResultCode(-1));
+        const auto storage = broker->PopInteractiveDataToGame();
+        if (storage == nullptr) {
+            rb.Push(ERR_NO_DATA_IN_CHANNEL);
             return;
         }
 
         rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<IStorage>(std::move(interactive_storage_stack.front()));
-
-        interactive_storage_stack.pop();
+        rb.PushIpcInterface<IStorage>(std::move(*storage));
 
         LOG_DEBUG(Service_AM, "called");
     }
@@ -680,7 +656,7 @@ private:
     void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
         IPC::ResponseBuilder rb{ctx, 2, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushCopyObjects(pop_out_data_event);
+        rb.PushCopyObjects(broker->GetNormalDataEvent());
 
         LOG_DEBUG(Service_AM, "called");
     }
@@ -688,17 +664,13 @@ private:
     void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
         IPC::ResponseBuilder rb{ctx, 2, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushCopyObjects(pop_interactive_out_data_event);
+        rb.PushCopyObjects(broker->GetInteractiveDataEvent());
 
         LOG_DEBUG(Service_AM, "called");
     }
 
     std::shared_ptr<Applets::Applet> applet;
-    std::queue<std::shared_ptr<IStorage>> storage_stack;
-    std::queue<std::shared_ptr<IStorage>> interactive_storage_stack;
-    Kernel::SharedPtr<Kernel::Event> state_changed_event;
-    Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
-    Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
+    std::shared_ptr<Applets::AppletDataBroker> broker;
 };
 
 void IStorage::Open(Kernel::HLERequestContext& ctx) {
@@ -740,9 +712,12 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
     const u64 offset{rp.Pop<u64>()};
     const std::vector<u8> data{ctx.ReadBuffer()};
 
-    const auto size = std::min<std::size_t>(data.size(), backing.buffer.size() - offset);
+    if (data.size() > backing.buffer.size() - offset) {
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
+    }
 
-    std::memcpy(&backing.buffer[offset], data.data(), size);
+    std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(RESULT_SUCCESS);
@@ -754,9 +729,12 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
 
     const u64 offset{rp.Pop<u64>()};
-    std::size_t size{ctx.GetWriteBufferSize()};
+    const std::size_t size{ctx.GetWriteBufferSize()};
 
-    size = std::min<std::size_t>(size, backing.buffer.size() - offset);
+    if (size > backing.buffer.size() - offset) {
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
+    }
 
     ctx.WriteBuffer(backing.buffer.data() + offset, size);
 
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index be950d320..c81bd59b2 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -4,21 +4,108 @@
 
 #include <cstring>
 #include "common/assert.h"
+#include "core/core.h"
 #include "core/frontend/applets/software_keyboard.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/server_port.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/applets.h"
 
 namespace Service::AM::Applets {
 
+AppletDataBroker::AppletDataBroker() {
+    auto& kernel = Core::System::GetInstance().Kernel();
+    state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+                                                "ILibraryAppletAccessor:StateChangedEvent");
+    pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+                                               "ILibraryAppletAccessor:PopDataOutEvent");
+    pop_interactive_out_data_event = Kernel::Event::Create(
+        kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
+}
+
+AppletDataBroker::~AppletDataBroker() = default;
+
+std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
+    if (out_channel.empty())
+        return nullptr;
+
+    auto out = std::move(out_channel.front());
+    out_channel.pop();
+    return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
+    if (in_channel.empty())
+        return nullptr;
+
+    auto out = std::move(in_channel.front());
+    in_channel.pop();
+    return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
+    if (out_interactive_channel.empty())
+        return nullptr;
+
+    auto out = std::move(out_interactive_channel.front());
+    out_interactive_channel.pop();
+    return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
+    if (in_interactive_channel.empty())
+        return nullptr;
+
+    auto out = std::move(in_interactive_channel.front());
+    in_interactive_channel.pop();
+    return out;
+}
+
+void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
+    in_channel.push(std::make_unique<IStorage>(storage));
+}
+
+void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
+    out_channel.push(std::make_unique<IStorage>(storage));
+    pop_out_data_event->Signal();
+}
+
+void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
+    in_interactive_channel.push(std::make_unique<IStorage>(storage));
+}
+
+void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
+    out_interactive_channel.push(std::make_unique<IStorage>(storage));
+    pop_interactive_out_data_event->Signal();
+}
+
+void AppletDataBroker::SignalStateChanged() const {
+    state_changed_event->Signal();
+}
+
+Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const {
+    return pop_out_data_event;
+}
+
+Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const {
+    return pop_interactive_out_data_event;
+}
+
+Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const {
+    return state_changed_event;
+}
+
 Applet::Applet() = default;
 
 Applet::~Applet() = default;
 
-void Applet::Initialize(std::queue<std::shared_ptr<IStorage>> storage) {
-    storage_stack = std::move(storage);
+void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
+    broker = std::move(broker_);
 
-    const auto common_data = storage_stack.front()->GetData();
-    storage_stack.pop();
+    const auto common = broker->PopNormalDataToApplet();
+    ASSERT(common != nullptr);
+
+    const auto common_data = common->GetData();
 
     ASSERT(common_data.size() >= sizeof(CommonArguments));
     std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index a6a9bf77b..136445649 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -8,35 +8,67 @@
 #include <memory>
 #include <queue>
 #include "common/swap.h"
+#include "core/hle/kernel/event.h"
 
 union ResultCode;
 
-namespace Frontend {
-class SoftwareKeyboardApplet;
-}
-
 namespace Service::AM {
 
 class IStorage;
 
 namespace Applets {
 
-using AppletStorageProxyFunction = std::function<void(IStorage)>;
-using AppletStateProxyFunction = std::function<void()>;
+class AppletDataBroker final {
+public:
+    AppletDataBroker();
+    ~AppletDataBroker();
+
+    std::unique_ptr<IStorage> PopNormalDataToGame();
+    std::unique_ptr<IStorage> PopNormalDataToApplet();
+
+    std::unique_ptr<IStorage> PopInteractiveDataToGame();
+    std::unique_ptr<IStorage> PopInteractiveDataToApplet();
+
+    void PushNormalDataFromGame(IStorage storage);
+    void PushNormalDataFromApplet(IStorage storage);
+
+    void PushInteractiveDataFromGame(IStorage storage);
+    void PushInteractiveDataFromApplet(IStorage storage);
+
+    void SignalStateChanged() const;
+
+    Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const;
+    Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const;
+    Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const;
+
+private:
+    // Queues are named from applet's perspective
+    std::queue<std::unique_ptr<IStorage>>
+        in_channel; // PopNormalDataToApplet and PushNormalDataFromGame
+    std::queue<std::unique_ptr<IStorage>>
+        out_channel; // PopNormalDataToGame and PushNormalDataFromApplet
+    std::queue<std::unique_ptr<IStorage>>
+        in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame
+    std::queue<std::unique_ptr<IStorage>>
+        out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet
+
+    Kernel::SharedPtr<Kernel::Event> state_changed_event;
+    Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet
+    Kernel::SharedPtr<Kernel::Event>
+        pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet
+};
 
 class Applet {
 public:
     Applet();
     virtual ~Applet();
 
-    virtual void Initialize(std::queue<std::shared_ptr<IStorage>> storage);
+    virtual void Initialize(std::shared_ptr<AppletDataBroker> broker);
 
     virtual bool TransactionComplete() const = 0;
     virtual ResultCode GetStatus() const = 0;
-    virtual void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) = 0;
-    virtual void Execute(AppletStorageProxyFunction out_data,
-                         AppletStorageProxyFunction out_interactive_data,
-                         AppletStateProxyFunction state) = 0;
+    virtual void ExecuteInteractive() = 0;
+    virtual void Execute() = 0;
 
     bool IsInitialized() const {
         return initialized;
@@ -54,7 +86,7 @@ protected:
     static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
 
     CommonArguments common_args;
-    std::queue<std::shared_ptr<IStorage>> storage_stack;
+    std::shared_ptr<AppletDataBroker> broker;
     bool initialized = false;
 };
 
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 816b5fb5f..ca9ef7e7d 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -42,22 +42,23 @@ SoftwareKeyboard::SoftwareKeyboard() = default;
 
 SoftwareKeyboard::~SoftwareKeyboard() = default;
 
-void SoftwareKeyboard::Initialize(std::queue<std::shared_ptr<IStorage>> storage_) {
+void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
     complete = false;
     initial_text.clear();
     final_data.clear();
 
-    Applet::Initialize(std::move(storage_));
+    Applet::Initialize(std::move(broker_));
 
-    ASSERT(storage_stack.size() >= 2);
-    const auto& keyboard_config = storage_stack.front()->GetData();
-    storage_stack.pop();
+    const auto keyboard_config_storage = broker->PopNormalDataToApplet();
+    ASSERT(keyboard_config_storage != nullptr);
+    const auto& keyboard_config = keyboard_config_storage->GetData();
 
     ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
     std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
 
-    const auto& work_buffer = storage_stack.front()->GetData();
-    storage_stack.pop();
+    const auto work_buffer_storage = broker->PopNormalDataToApplet();
+    ASSERT(work_buffer_storage != nullptr);
+    const auto& work_buffer = work_buffer_storage->GetData();
 
     if (config.initial_string_size == 0)
         return;
@@ -76,10 +77,12 @@ ResultCode SoftwareKeyboard::GetStatus() const {
     return status;
 }
 
-void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) {
+void SoftwareKeyboard::ExecuteInteractive() {
     if (complete)
         return;
 
+    const auto storage = broker->PopInteractiveDataToApplet();
+    ASSERT(storage != nullptr);
     const auto data = storage->GetData();
     const auto status = static_cast<bool>(data[0]);
 
@@ -91,15 +94,14 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage)
         std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
         std::memcpy(string.data(), data.data() + 4, string.size() * 2);
         frontend.SendTextCheckDialog(
-            Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state);
+            Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
+            [this] { broker->SignalStateChanged(); });
     }
 }
 
-void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
-                               AppletStorageProxyFunction out_interactive_data,
-                               AppletStateProxyFunction state) {
+void SoftwareKeyboard::Execute() {
     if (complete) {
-        out_data(IStorage{final_data});
+        broker->PushNormalDataFromApplet(IStorage{final_data});
         return;
     }
 
@@ -107,9 +109,6 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
 
     const auto parameters = ConvertToFrontendParameters(config, initial_text);
 
-    this->out_data = out_data;
-    this->out_interactive_data = out_interactive_data;
-    this->state = state;
     frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
                          parameters);
 }
@@ -147,19 +146,19 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
         final_data = output_main;
 
         if (complete) {
-            out_data(IStorage{output_main});
+            broker->PushNormalDataFromApplet(IStorage{output_main});
         } else {
-            out_data(IStorage{output_main});
-            out_interactive_data(IStorage{output_sub});
+            broker->PushNormalDataFromApplet(IStorage{output_main});
+            broker->PushInteractiveDataFromApplet(IStorage{output_sub});
         }
 
-        state();
+        broker->SignalStateChanged();
     } else {
         status = ResultCode(-1);
         output_main[0] = 1;
         complete = true;
-        out_data(IStorage{output_main});
-        state();
+        broker->PushNormalDataFromApplet(IStorage{output_main});
+        broker->SignalStateChanged();
     }
 }
 } // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index e0a9479c2..405c58851 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -50,14 +50,12 @@ public:
     SoftwareKeyboard();
     ~SoftwareKeyboard() override;
 
-    void Initialize(std::queue<std::shared_ptr<IStorage>> storage) override;
+    void Initialize(std::shared_ptr<AppletDataBroker> broker) override;
 
     bool TransactionComplete() const override;
     ResultCode GetStatus() const override;
-    void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) override;
-    void Execute(AppletStorageProxyFunction out_data,
-                 AppletStorageProxyFunction out_interactive_data,
-                 AppletStateProxyFunction state) override;
+    void ExecuteInteractive() override;
+    void Execute() override;
 
     void WriteText(std::optional<std::u16string> text);
 
@@ -67,10 +65,6 @@ private:
     bool complete = false;
     std::vector<u8> final_data;
     ResultCode status = ResultCode(-1);
-
-    AppletStorageProxyFunction out_data;
-    AppletStorageProxyFunction out_interactive_data;
-    AppletStateProxyFunction state;
 };
 
 } // namespace Service::AM::Applets