diff --git a/meson.build b/meson.build
index 8695e3ff1..1716898c7 100644
--- a/meson.build
+++ b/meson.build
@@ -279,6 +279,8 @@ sources = [
   'src/command/PartitionCommands.cxx',
   'src/command/OtherCommands.cxx',
   'src/command/CommandListBuilder.cxx',
+  'src/config/PartitionConfig.cxx',
+  'src/config/PlayerConfig.cxx',
   'src/Idle.cxx',
   'src/IdleFlags.cxx',
   'src/decoder/Thread.cxx',
diff --git a/src/Main.cxx b/src/Main.cxx
index 77575a008..bf59eb26f 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -32,7 +32,6 @@
 #include "command/AllCommands.hxx"
 #include "Partition.hxx"
 #include "tag/Config.hxx"
-#include "ReplayGainGlobal.hxx"
 #include "IdleFlags.hxx"
 #include "Log.hxx"
 #include "LogInit.hxx"
@@ -46,7 +45,6 @@
 #include "playlist/PlaylistRegistry.hxx"
 #include "zeroconf/Glue.hxx"
 #include "decoder/DecoderList.hxx"
-#include "pcm/AudioParser.hxx"
 #include "pcm/Convert.hxx"
 #include "unix/SignalHandlers.hxx"
 #include "thread/Slack.hxx"
@@ -60,6 +58,7 @@
 #include "config/Option.hxx"
 #include "config/Domain.hxx"
 #include "config/Parser.hxx"
+#include "config/PartitionConfig.hxx"
 #include "util/RuntimeError.hxx"
 #include "util/ScopeExit.hxx"
 
@@ -116,15 +115,6 @@
 #include <clocale>
 #endif
 
-static constexpr size_t KILOBYTE = 1024;
-static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
-
-static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
-
-static constexpr
-size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
-				  64 * KILOBYTE);
-
 #ifdef ANDROID
 Context *context;
 LogListener *logListener;
@@ -132,13 +122,6 @@ LogListener *logListener;
 
 Instance *global_instance;
 
-struct Config {
-	ReplayGainConfig replay_gain;
-
-	explicit Config(const ConfigData &raw)
-		:replay_gain(LoadReplayGainConfig(raw)) {}
-};
-
 #ifdef ENABLE_DAEMON
 
 static void
@@ -293,53 +276,11 @@ glue_state_file_init(Instance &instance, const ConfigData &raw_config)
 static void
 initialize_decoder_and_player(Instance &instance,
 			      const ConfigData &config,
-			      const ReplayGainConfig &replay_gain_config)
+			      const PartitionConfig &partition_config)
 {
-	const ConfigParam *param;
-
-	size_t buffer_size;
-	param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
-	if (param != nullptr) {
-		buffer_size = param->With([](const char *s){
-			size_t result = ParseSize(s, KILOBYTE);
-			if (result <= 0)
-				throw FormatRuntimeError("buffer size \"%s\" is not a "
-							 "positive integer", s);
-
-			if (result < MIN_BUFFER_SIZE) {
-				FmtWarning(config_domain, "buffer size {} is too small, using {} bytes instead",
-					   result, MIN_BUFFER_SIZE);
-				result = MIN_BUFFER_SIZE;
-			}
-
-			return result;
-		});
-	} else
-		buffer_size = DEFAULT_BUFFER_SIZE;
-
-	const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
-
-	if (buffered_chunks >= 1 << 15)
-		throw FormatRuntimeError("buffer size \"%lu\" is too big",
-					 (unsigned long)buffer_size);
-
-	const unsigned max_length =
-		config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
-				   DEFAULT_PLAYLIST_MAX_LENGTH);
-
-	AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
-		if (s == nullptr)
-			return AudioFormat::Undefined();
-
-		return ParseAudioFormat(s, true);
-	});
-
 	instance.partitions.emplace_back(instance,
 					 "default",
-					 max_length,
-					 buffered_chunks,
-					 configured_audio_format,
-					 replay_gain_config);
+					 partition_config);
 	auto &partition = instance.partitions.back();
 
 	partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){
@@ -392,7 +333,7 @@ MainConfigured(const CommandLineOptions &options,
 #endif
 
 	InitPathParser(raw_config);
-	const Config config(raw_config);
+	const PartitionConfig partition_config{raw_config};
 
 #ifdef ENABLE_DAEMON
 	glue_daemonize_init(options, raw_config);
@@ -426,7 +367,7 @@ MainConfigured(const CommandLineOptions &options,
 	}
 
 	initialize_decoder_and_player(instance,
-				      raw_config, config.replay_gain);
+				      raw_config, partition_config);
 
 	listen_global_init(raw_config, *instance.partitions.front().listener);
 
@@ -465,7 +406,7 @@ MainConfigured(const CommandLineOptions &options,
 		partition.outputs.Configure(instance.io_thread.GetEventLoop(),
 					    instance.rtio_thread.GetEventLoop(),
 					    raw_config,
-					    config.replay_gain);
+					    partition_config.player.replay_gain);
 		partition.UpdateEffectiveReplayGainMode();
 	}
 
diff --git a/src/Partition.cxx b/src/Partition.cxx
index cf3396652..e2967daa4 100644
--- a/src/Partition.cxx
+++ b/src/Partition.cxx
@@ -21,6 +21,7 @@
 #include "Partition.hxx"
 #include "Instance.hxx"
 #include "Log.hxx"
+#include "config/PartitionConfig.hxx"
 #include "lib/fmt/ExceptionFormatter.hxx"
 #include "song/DetachedSong.hxx"
 #include "mixer/Volume.hxx"
@@ -34,21 +35,18 @@ static constexpr Domain cache_domain("cache");
 
 Partition::Partition(Instance &_instance,
 		     const char *_name,
-		     unsigned max_length,
-		     unsigned buffer_chunks,
-		     AudioFormat configured_audio_format,
-		     const ReplayGainConfig &replay_gain_config) noexcept
+		     const PartitionConfig &_config) noexcept
 	:instance(_instance),
 	 name(_name),
+	 config(_config),
 	 listener(new ClientListener(instance.event_loop, *this)),
 	 idle_monitor(instance.event_loop, BIND_THIS_METHOD(OnIdleMonitor)),
 	 global_events(instance.event_loop, BIND_THIS_METHOD(OnGlobalEvent)),
-	 playlist(max_length, *this),
+	 playlist(config.queue.max_length, *this),
 	 outputs(pc, *this),
 	 pc(*this, outputs,
 	    instance.input_cache.get(),
-	    buffer_chunks,
-	    configured_audio_format, replay_gain_config)
+	    config.player)
 {
 	UpdateEffectiveReplayGainMode();
 }
diff --git a/src/Partition.hxx b/src/Partition.hxx
index b90a01101..7679b5879 100644
--- a/src/Partition.hxx
+++ b/src/Partition.hxx
@@ -38,6 +38,7 @@
 #include <string>
 #include <memory>
 
+struct PartitionConfig;
 struct Instance;
 struct RangeArg;
 class MultipleOutputs;
@@ -58,6 +59,8 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
 
 	const std::string name;
 
+	const PartitionConfig &config;
+
 	std::unique_ptr<ClientListener> listener;
 
 	boost::intrusive::list<Client,
@@ -82,10 +85,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
 
 	Partition(Instance &_instance,
 		  const char *_name,
-		  unsigned max_length,
-		  unsigned buffer_chunks,
-		  AudioFormat configured_audio_format,
-		  const ReplayGainConfig &replay_gain_config) noexcept;
+		  const PartitionConfig &_config) noexcept;
 
 	~Partition() noexcept;
 
diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx
index 7035136df..1fb1b9fcb 100644
--- a/src/PlaylistFile.cxx
+++ b/src/PlaylistFile.cxx
@@ -33,6 +33,7 @@
 #include "config/Data.hxx"
 #include "config/Option.hxx"
 #include "config/Defaults.hxx"
+#include "config/QueueConfig.hxx"
 #include "Idle.hxx"
 #include "fs/Limits.hxx"
 #include "fs/Traits.hxx"
@@ -55,7 +56,7 @@ spl_global_init(const ConfigData &config)
 {
 	playlist_max_length =
 		config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
-				   DEFAULT_PLAYLIST_MAX_LENGTH);
+				   QueueConfig::DEFAULT_MAX_LENGTH);
 
 	playlist_saveAbsolutePaths =
 		config.GetBool(ConfigOption::SAVE_ABSOLUTE_PATHS,
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index 10426a2b2..83108b7dc 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -101,11 +101,7 @@ handle_newpartition(Client &client, Request request, Response &response)
 	}
 
 	instance.partitions.emplace_back(instance, name,
-					 // TODO: use real configuration
-					 16384,
-					 1024,
-					 AudioFormat::Undefined(),
-					 ReplayGainConfig());
+					 client.GetPartition().config);
 	auto &partition = instance.partitions.back();
 	partition.UpdateEffectiveReplayGainMode();
 
diff --git a/src/config/Defaults.hxx b/src/config/Defaults.hxx
index a5b8467e5..eaa16ace8 100644
--- a/src/config/Defaults.hxx
+++ b/src/config/Defaults.hxx
@@ -20,7 +20,6 @@
 #ifndef MPD_CONFIG_DEFAULTS_HXX
 #define MPD_CONFIG_DEFAULTS_HXX
 
-static constexpr unsigned DEFAULT_PLAYLIST_MAX_LENGTH = 16 * 1024;
 static constexpr bool DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS = false;
 
 #endif
diff --git a/src/config/PartitionConfig.cxx b/src/config/PartitionConfig.cxx
new file mode 100644
index 000000000..974e7562b
--- /dev/null
+++ b/src/config/PartitionConfig.cxx
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003-2021 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "PartitionConfig.hxx"
+#include "Data.hxx"
+
+PartitionConfig::PartitionConfig(const ConfigData &config)
+	:player(config)
+{
+	queue.max_length =
+		config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
+				   QueueConfig::DEFAULT_MAX_LENGTH);
+}
diff --git a/src/config/PartitionConfig.hxx b/src/config/PartitionConfig.hxx
new file mode 100644
index 000000000..21192eab7
--- /dev/null
+++ b/src/config/PartitionConfig.hxx
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2003-2021 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include "QueueConfig.hxx"
+#include "PlayerConfig.hxx"
+
+struct PartitionConfig {
+	QueueConfig queue;
+	PlayerConfig player;
+
+	PartitionConfig() = default;
+
+	explicit PartitionConfig(const ConfigData &config);
+};
diff --git a/src/config/PlayerConfig.cxx b/src/config/PlayerConfig.cxx
new file mode 100644
index 000000000..206420949
--- /dev/null
+++ b/src/config/PlayerConfig.cxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2003-2021 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "PartitionConfig.hxx"
+#include "Data.hxx"
+#include "Domain.hxx"
+#include "Parser.hxx"
+#include "pcm/AudioParser.hxx"
+#include "util/RuntimeError.hxx"
+#include "Log.hxx"
+#include "MusicChunk.hxx"
+#include "ReplayGainGlobal.hxx"
+
+static constexpr
+size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
+				  64 * KILOBYTE);
+
+PlayerConfig::PlayerConfig(const ConfigData &config)
+{
+	size_t buffer_size = PlayerConfig::DEFAULT_BUFFER_SIZE;
+	if (auto *param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE)) {
+		buffer_size = param->With([](const char *s){
+			size_t result = ParseSize(s, KILOBYTE);
+			if (result <= 0)
+				throw FormatRuntimeError("buffer size \"%s\" is not a "
+							 "positive integer", s);
+
+			if (result < MIN_BUFFER_SIZE) {
+				FmtWarning(config_domain, "buffer size {} is too small, using {} bytes instead",
+					   result, MIN_BUFFER_SIZE);
+				result = MIN_BUFFER_SIZE;
+			}
+
+			return result;
+		});
+	}
+
+	buffer_chunks = buffer_size / CHUNK_SIZE;
+	if (buffer_chunks >= 1 << 15)
+		throw FormatRuntimeError("buffer size \"%lu\" is too big",
+					 (unsigned long)buffer_size);
+
+	audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
+		if (s == nullptr)
+			return AudioFormat::Undefined();
+
+		return ParseAudioFormat(s, true);
+	});
+
+	replay_gain = LoadReplayGainConfig(config);
+}
diff --git a/src/config/PlayerConfig.hxx b/src/config/PlayerConfig.hxx
new file mode 100644
index 000000000..07bbcf089
--- /dev/null
+++ b/src/config/PlayerConfig.hxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2021 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include "pcm/AudioFormat.hxx"
+#include "ReplayGainConfig.hxx"
+
+struct ConfigData;
+
+static constexpr size_t KILOBYTE = 1024;
+static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
+
+struct PlayerConfig {
+	static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
+
+	unsigned buffer_chunks = DEFAULT_BUFFER_SIZE;
+
+	/**
+	 * The "audio_output_format" setting.
+	 */
+	AudioFormat audio_format = AudioFormat::Undefined();
+
+	ReplayGainConfig replay_gain;
+
+	PlayerConfig() = default;
+
+	explicit PlayerConfig(const ConfigData &config);
+};
diff --git a/src/config/QueueConfig.hxx b/src/config/QueueConfig.hxx
new file mode 100644
index 000000000..65ecb4fa3
--- /dev/null
+++ b/src/config/QueueConfig.hxx
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2003-2021 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+struct QueueConfig {
+	static constexpr unsigned DEFAULT_MAX_LENGTH = 16 * 1024;
+
+	unsigned max_length = DEFAULT_MAX_LENGTH;
+};
diff --git a/src/player/Control.cxx b/src/player/Control.cxx
index f4650bef6..5e919aa1f 100644
--- a/src/player/Control.cxx
+++ b/src/player/Control.cxx
@@ -28,15 +28,12 @@
 PlayerControl::PlayerControl(PlayerListener &_listener,
 			     PlayerOutputs &_outputs,
 			     InputCacheManager *_input_cache,
-			     unsigned _buffer_chunks,
-			     AudioFormat _configured_audio_format,
-			     const ReplayGainConfig &_replay_gain_config) noexcept
+			     const PlayerConfig &_config) noexcept
 	:listener(_listener), outputs(_outputs),
 	 input_cache(_input_cache),
-	 buffer_chunks(_buffer_chunks),
-	 configured_audio_format(_configured_audio_format),
-	 thread(BIND_THIS_METHOD(RunThread)),
-	 replay_gain_config(_replay_gain_config)
+	 config(_config),
+	 thread(BIND_THIS_METHOD(RunThread))
+
 {
 }
 
diff --git a/src/player/Control.hxx b/src/player/Control.hxx
index 73f026496..26373f2a7 100644
--- a/src/player/Control.hxx
+++ b/src/player/Control.hxx
@@ -21,13 +21,13 @@
 #define MPD_PLAYER_CONTROL_HXX
 
 #include "output/Client.hxx"
+#include "config/PlayerConfig.hxx"
 #include "pcm/AudioFormat.hxx"
 #include "thread/Mutex.hxx"
 #include "thread/Cond.hxx"
 #include "thread/Thread.hxx"
 #include "CrossFade.hxx"
 #include "Chrono.hxx"
-#include "ReplayGainConfig.hxx"
 #include "ReplayGainMode.hxx"
 #include "MusicChunkPtr.hxx"
 
@@ -36,6 +36,7 @@
 #include <memory>
 
 struct Tag;
+struct PlayerConfig;
 class PlayerListener;
 class PlayerOutputs;
 class InputCacheManager;
@@ -118,12 +119,7 @@ class PlayerControl final : public AudioOutputClient {
 
 	InputCacheManager *const input_cache;
 
-	const unsigned buffer_chunks;
-
-	/**
-	 * The "audio_output_format" setting.
-	 */
-	const AudioFormat configured_audio_format;
+	const PlayerConfig config;
 
 	/**
 	 * The handle of the player thread.
@@ -229,17 +225,13 @@ class PlayerControl final : public AudioOutputClient {
 
 	CrossFadeSettings cross_fade;
 
-	const ReplayGainConfig replay_gain_config;
-
 	FloatDuration total_play_time = FloatDuration::zero();
 
 public:
 	PlayerControl(PlayerListener &_listener,
 		      PlayerOutputs &_outputs,
 		      InputCacheManager *_input_cache,
-		      unsigned buffer_chunks,
-		      AudioFormat _configured_audio_format,
-		      const ReplayGainConfig &_replay_gain_config) noexcept;
+		      const PlayerConfig &_config) noexcept;
 	~PlayerControl() noexcept;
 
 	void Kill() noexcept;
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 7d1416837..03012fcf2 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -1165,11 +1165,11 @@ try {
 
 	DecoderControl dc(mutex, cond,
 			  input_cache,
-			  configured_audio_format,
-			  replay_gain_config);
+			  config.audio_format,
+			  config.replay_gain);
 	dc.StartThread();
 
-	MusicBuffer buffer(buffer_chunks);
+	MusicBuffer buffer{config.buffer_chunks};
 
 	std::unique_lock<Mutex> lock(mutex);