diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index ba6acf28e..84f9c03a7 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -56,20 +56,8 @@ void AddAddressSpace(Kernel::VMManager& address_space) {
 }
 
 void SelectSink(std::string sink_id) {
-    auto iter =
-        std::find_if(g_sink_details.begin(), g_sink_details.end(),
-                     [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
-
-    if (sink_id == "auto" || iter == g_sink_details.end()) {
-        if (sink_id != "auto") {
-            LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
-        }
-        // Auto-select.
-        // g_sink_details is ordered in terms of desirability, with the best choice at the front.
-        iter = g_sink_details.begin();
-    }
-
-    DSP::HLE::SetSink(iter->factory());
+    const SinkDetails& sink_details = GetSinkDetails(sink_id);
+    DSP::HLE::SetSink(sink_details.factory());
 }
 
 void EnableStretching(bool enable) {
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index e7668438c..c732926a2 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -23,6 +23,12 @@ public:
     size_t SamplesInQueue() const override {
         return 0;
     }
+
+    void SetDevice(int device_id) override {}
+
+    std::vector<std::string> GetDeviceList() const override {
+        return {};
+    }
 };
 
 } // namespace AudioCore
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
index 4b66cd826..933c5f16d 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -4,12 +4,12 @@
 
 #include <list>
 #include <numeric>
-#include <vector>
 #include <SDL.h>
 #include "audio_core/audio_core.h"
 #include "audio_core/sdl2_sink.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
+#include "core/settings.h"
 
 namespace AudioCore {
 
@@ -42,10 +42,24 @@ SDL2Sink::SDL2Sink() : impl(std::make_unique<Impl>()) {
     SDL_AudioSpec obtained_audiospec;
     SDL_zero(obtained_audiospec);
 
-    impl->audio_device_id =
-        SDL_OpenAudioDevice(nullptr, false, &desired_audiospec, &obtained_audiospec, 0);
+    int device_count = SDL_GetNumAudioDevices(0);
+    device_list.clear();
+    for (int i = 0; i < device_count; ++i) {
+        device_list.push_back(SDL_GetAudioDeviceName(i, 0));
+    }
+
+    const char* device = nullptr;
+
+    if (device_count >= 1 && Settings::values.audio_device_id != "auto" &&
+        !Settings::values.audio_device_id.empty()) {
+        device = Settings::values.audio_device_id.c_str();
+    }
+
+    impl->audio_device_id = SDL_OpenAudioDevice(device, false, &desired_audiospec,
+                                                &obtained_audiospec, SDL_AUDIO_ALLOW_ANY_CHANGE);
     if (impl->audio_device_id <= 0) {
-        LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with: %s", SDL_GetError());
+        LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code %d for device \"%s\"",
+                     impl->audio_device_id, Settings::values.audio_device_id.c_str());
         return;
     }
 
@@ -69,6 +83,10 @@ unsigned int SDL2Sink::GetNativeSampleRate() const {
     return impl->sample_rate;
 }
 
+std::vector<std::string> SDL2Sink::GetDeviceList() const {
+    return device_list;
+}
+
 void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) {
     if (impl->audio_device_id <= 0)
         return;
@@ -96,6 +114,10 @@ size_t SDL2Sink::SamplesInQueue() const {
     return total_size;
 }
 
+void SDL2Sink::SetDevice(int device_id) {
+    this->device_id = device_id;
+}
+
 void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) {
     Impl* impl = reinterpret_cast<Impl*>(impl_);
 
diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h
index ccd0f7c7e..ce75733b7 100644
--- a/src/audio_core/sdl2_sink.h
+++ b/src/audio_core/sdl2_sink.h
@@ -21,9 +21,14 @@ public:
 
     size_t SamplesInQueue() const override;
 
+    std::vector<std::string> GetDeviceList() const override;
+    void SetDevice(int device_id);
+
 private:
     struct Impl;
     std::unique_ptr<Impl> impl;
+    int device_id;
+    std::vector<std::string> device_list;
 };
 
 } // namespace AudioCore
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
index 08f3bab5b..558c8c0fe 100644
--- a/src/audio_core/sink.h
+++ b/src/audio_core/sink.h
@@ -31,6 +31,15 @@ public:
 
     /// Samples enqueued that have not been played yet.
     virtual std::size_t SamplesInQueue() const = 0;
+
+    /**
+     * Sets the desired output device.
+     * @paran device_id Id of the desired device.
+     */
+    virtual void SetDevice(int device_id) = 0;
+
+    /// Returns the list of available devices.
+    virtual std::vector<std::string> GetDeviceList() const = 0;
 };
 
 } // namespace
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 95ccc9e9d..6972395af 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <algorithm>
 #include <memory>
 #include <vector>
 #include "audio_core/null_sink.h"
@@ -9,6 +10,7 @@
 #ifdef HAVE_SDL2
 #include "audio_core/sdl2_sink.h"
 #endif
+#include "common/logging/log.h"
 
 namespace AudioCore {
 
@@ -20,4 +22,21 @@ const std::vector<SinkDetails> g_sink_details = {
     {"null", []() { return std::make_unique<NullSink>(); }},
 };
 
+const SinkDetails& GetSinkDetails(std::string sink_id) {
+    auto iter =
+        std::find_if(g_sink_details.begin(), g_sink_details.end(),
+                     [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
+
+    if (sink_id == "auto" || iter == g_sink_details.end()) {
+        if (sink_id != "auto") {
+            LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
+        }
+        // Auto-select.
+        // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+        iter = g_sink_details.begin();
+    }
+
+    return *iter;
+}
+
 } // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
index 4b30cf835..9d3735171 100644
--- a/src/audio_core/sink_details.h
+++ b/src/audio_core/sink_details.h
@@ -24,4 +24,6 @@ struct SinkDetails {
 
 extern const std::vector<SinkDetails> g_sink_details;
 
+const SinkDetails& GetSinkDetails(std::string sink_id);
+
 } // namespace AudioCore
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 1d0faf193..827c90e55 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -82,6 +82,7 @@ void Config::ReadValues() {
     Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
     Settings::values.enable_audio_stretching =
         sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
+    Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
 
     // Data Storage
     Settings::values.use_virtual_sd =
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 7996813b4..d728fb9e8 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -91,6 +91,10 @@ output_engine =
 # 0: No, 1 (default): Yes
 enable_audio_stretching =
 
+# Which audio device to use.
+# auto (default): Auto-select
+output_device =
+
 [Data Storage]
 # Whether to create a virtual SD card.
 # 1 (default): Yes, 0: No
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 8021667d0..f776e16b2 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -63,6 +63,8 @@ void Config::ReadValues() {
     Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
     Settings::values.enable_audio_stretching =
         qt_config->value("enable_audio_stretching", true).toBool();
+    Settings::values.audio_device_id =
+        qt_config->value("output_device", "auto").toString().toStdString();
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
@@ -169,6 +171,7 @@ void Config::SaveValues() {
     qt_config->beginGroup("Audio");
     qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
     qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
+    qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configure_audio.cpp
index 3cdd4c780..3ddcf9232 100644
--- a/src/citra_qt/configure_audio.cpp
+++ b/src/citra_qt/configure_audio.cpp
@@ -2,6 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <memory>
+#include "audio_core/audio_core.h"
+#include "audio_core/sink.h"
 #include "audio_core/sink_details.h"
 #include "citra_qt/configure_audio.h"
 #include "core/settings.h"
@@ -18,6 +21,8 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
     }
 
     this->setConfiguration();
+    connect(ui->output_sink_combo_box, SIGNAL(currentIndexChanged(int)), this,
+            SLOT(updateAudioDevices(int)));
 }
 
 ConfigureAudio::~ConfigureAudio() {}
@@ -33,6 +38,19 @@ void ConfigureAudio::setConfiguration() {
     ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
 
     ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
+
+    // The device list cannot be pre-populated (nor listed) until the output sink is known.
+    updateAudioDevices(new_sink_index);
+
+    int new_device_index = -1;
+    for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
+        if (ui->audio_device_combo_box->itemText(index).toStdString() ==
+            Settings::values.audio_device_id) {
+            new_device_index = index;
+            break;
+        }
+    }
+    ui->audio_device_combo_box->setCurrentIndex(new_device_index);
 }
 
 void ConfigureAudio::applyConfiguration() {
@@ -40,5 +58,20 @@ void ConfigureAudio::applyConfiguration() {
         ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
             .toStdString();
     Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
+    Settings::values.audio_device_id =
+        ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
+            .toStdString();
     Settings::Apply();
 }
+
+void ConfigureAudio::updateAudioDevices(int sink_index) {
+    ui->audio_device_combo_box->clear();
+    ui->audio_device_combo_box->addItem("auto");
+
+    std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
+    std::vector<std::string> device_list =
+        AudioCore::GetSinkDetails(sink_id).factory()->GetDeviceList();
+    for (const auto& device : device_list) {
+        ui->audio_device_combo_box->addItem(device.c_str());
+    }
+}
diff --git a/src/citra_qt/configure_audio.h b/src/citra_qt/configure_audio.h
index 51df2e27b..8190e694f 100644
--- a/src/citra_qt/configure_audio.h
+++ b/src/citra_qt/configure_audio.h
@@ -20,6 +20,9 @@ public:
 
     void applyConfiguration();
 
+public slots:
+    void updateAudioDevices(int sink_index);
+
 private:
     void setConfiguration();
 
diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configure_audio.ui
index 3e2b4635f..dd870eb61 100644
--- a/src/citra_qt/configure_audio.ui
+++ b/src/citra_qt/configure_audio.ui
@@ -35,6 +35,21 @@
         </property>
        </widget>
       </item>
+      <item>
+       <layout class="QHBoxLayout">
+        <item>
+         <widget class="QLabel">
+          <property name="text">
+           <string>Audio Device:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="audio_device_combo_box">
+         </widget>
+        </item>
+       </layout>
+      </item>
      </layout>
     </widget>
    </item>
diff --git a/src/core/settings.h b/src/core/settings.h
index 8dbda653a..e22ce0f16 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -104,6 +104,7 @@ struct Values {
     // Audio
     std::string sink_id;
     bool enable_audio_stretching;
+    std::string audio_device_id;
 
     // Debugging
     bool use_gdbstub;