diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
index bfd574a25070..01e0188468c1 100644
--- a/include/libcamera/camera.h
+++ b/include/libcamera/camera.h
@@ -44,7 +44,7 @@ public:
 
 	const std::set<Stream *> &streams() const;
 	std::map<Stream *, StreamConfiguration>
-	streamConfiguration(std::set<Stream *> &streams);
+	streamConfiguration(std::list<StreamConfiguration> &configs);
 	int configureStreams(std::map<Stream *, StreamConfiguration> &config);
 
 	int allocateBuffers();
diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index 4608c2bc6f3c..fd94629e0726 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -5,6 +5,7 @@
  * main.cpp - cam - The libcamera swiss army knife
  */
 
+#include <list>
 #include <iomanip>
 #include <iostream>
 #include <map>
@@ -90,39 +91,42 @@ static int configureStreams(Camera *camera, std::set<Stream *> &streams,
 			    std::map<Stream *, StreamConfiguration> &config)
 {
 	KeyValueParser::Options format = options[OptFormat];
-	auto it = streams.begin();
-	Stream *output = *it;
-	Stream *viewfinder = *(++it);
-
-	std::map<Stream *, StreamConfiguration> defaultConfig =
-		camera->streamConfiguration(streams);
+	std::list<StreamConfiguration> streamConfs;
 
+	StreamConfiguration outputConfig = {};
 	if (options.isSet(OptFormat)) {
 		if (format.isSet("width"))
-			defaultConfig[output].width = format["width"];
+			outputConfig.width = format["width"];
 
 		if (format.isSet("height"))
-			defaultConfig[output].height = format["height"];
+			outputConfig.height = format["height"];
 
 		/* TODO: Translate 4CC string to ID. */
 		if (format.isSet("pixelformat"))
-			defaultConfig[output].pixelFormat = format["pixelformat"];
+			outputConfig.pixelFormat = format["pixelformat"];
 	}
+	outputConfig.hints.push_front(STILL_CAPTURE);
+	streamConfs.push_back(outputConfig);
 
-	/* Configure the secondary output stream. */
-	defaultConfig[viewfinder].width = 640;
-	defaultConfig[viewfinder].height = 480;
+	StreamConfiguration vfConfig = {};
+	vfConfig.hints.push_front(VIEWFINDER);
+	streamConfs.push_back(vfConfig);
 
-	/*
-	 * HACK: Select which stream to capture: use output if required,
-	 * use viewfinder if required or if no option has been specified
-	 * from the command line.
-	 */
-	if (options.isSet(OptOutput))
-		config[output] = defaultConfig[output];
-	if (options.isSet(OptViefinder) ||
-	    (!options.isSet(OptViefinder) && !options.isSet(OptOutput)))
-		config[viewfinder] = defaultConfig[viewfinder];
+	config = camera->streamConfiguration(streamConfs);
+	if (config.empty()) {
+		std::cout << "Cannot configure the requested streams"
+			  << std::endl;
+		return -EINVAL;
+	}
+
+	for (auto &map : config) {
+		StreamConfiguration *c = &map.second;
+
+		if (c->supports(VIEWFINDER)) {
+			c->width = 640;
+			c->height = 480;
+		}
+	}
 
 	return camera->configureStreams(config);
 }
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 99eb0e6876f0..f2ae3d3e2d9a 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -346,32 +346,30 @@ const std::set<Stream *> &Camera::streams() const
 
 /**
  * \brief Retrieve a group of stream configurations
- * \param[in] streams A map of stream IDs and configurations to setup
+ * \param[in] configs A set of requested stream configurations
  *
- * Retrieve the camera's configuration for a specified group of streams. The
- * caller can specifies which of the camera's streams to retrieve configuration
- * from by populating \a streams.
- *
- * The easiest way to populate the array of streams to fetch configuration from
- * is to first retrieve the camera's full array of stream with streams() and
- * then potentially trim it down to only contain the streams the caller
- * are interested in.
+ * Retrieve a list of streams and associated default configurations in the
+ * camera. The caller specifies the properties a stream shall satisfy by
+ * populating \a config and the camera associates each supplied configuration
+ * with a stream that matches the requested properties. The requested
+ * per-stream configuration might be modified by the camera to report the
+ * stream default parameters. The callers of this function are free to adjust
+ * the default paramters and provide such configuration to the
+ * configureStreams() method.
  *
  * \return A map of successfully retrieved stream IDs and configurations or an
  * empty list on error.
  */
 std::map<Stream *, StreamConfiguration>
-Camera::streamConfiguration(std::set<Stream *> &streams)
+Camera::streamConfiguration(std::list<StreamConfiguration> &configs)
 {
-	if (disconnected_ || !streams.size())
+	if (disconnected_ || !configs.size())
 		return std::map<Stream *, StreamConfiguration>{};
 
-	for (Stream *stream : streams) {
-		if (streams_.find(stream) == streams_.end())
-			return std::map<Stream *, StreamConfiguration>{};
-	}
+	if (configs.size() > streams_.size())
+		return std::map<Stream *, StreamConfiguration>{};
 
-	return pipe_->streamConfiguration(this, streams);
+	return pipe_->streamConfiguration(this, configs);
 }
 
 /**
diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h
index 6cdadcbdc3ea..ff9f265fe880 100644
--- a/src/libcamera/include/pipeline_handler.h
+++ b/src/libcamera/include/pipeline_handler.h
@@ -56,7 +56,8 @@ public:
 	virtual bool match(DeviceEnumerator *enumerator) = 0;
 
 	virtual std::map<Stream *, StreamConfiguration>
-	streamConfiguration(Camera *camera, std::set<Stream *> &streams) = 0;
+	streamConfiguration(Camera *camera,
+			    std::list<StreamConfiguration> &config) = 0;
 	virtual int configureStreams(Camera *camera,
 				     std::map<Stream *, StreamConfiguration> &config) = 0;
 
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 46479944a4da..52583b2beefd 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -197,7 +197,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -318,36 +318,66 @@ PipelineHandlerIPU3::~PipelineHandlerIPU3()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerIPU3::streamConfiguration(Camera *camera,
-					 std::set<Stream *> &streams)
+					 std::list<StreamConfiguration> &confs)
 {
-	std::map<Stream *, StreamConfiguration> configs;
+	std::map<Stream *, StreamConfiguration> configs = {};
 	IPU3CameraData *data = cameraData(camera);
-	StreamConfiguration config = {};
+
+	std::list<Stream *> availableStreams;
+	availableStreams.push_front(&data->outStream_);
+	availableStreams.push_front(&data->vfStream_);
 
 	/*
-	 * FIXME: Soraka: the maximum resolution reported by both sensors
-	 * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as
-	 * default configurations but they're not correctly processed by the
-	 * ImgU. Resolutions up tp 2560x1920 have been validated.
-	 *
-	 * \todo Clarify ImgU alignement requirements.
+	 * Try to match all the requested stream configurations with all
+	 * the streams available in the camera.
 	 */
-	config.width = 2560;
-	config.height = 1920;
-	config.pixelFormat = V4L2_PIX_FMT_NV12;
-	config.bufferCount = IPU3_BUFFER_COUNT;
-
-	configs[&data->outStream_] = config;
-	LOG(IPU3, Debug)
-		<< "Stream 'output' format set to " << config.width << "x"
-		<< config.height << "-0x" << std::hex << std::setfill('0')
-		<< std::setw(8) << config.pixelFormat;
-
-	configs[&data->vfStream_] = config;
-	LOG(IPU3, Debug)
-		<< "Stream 'viewfinder' format set to " << config.width << "x"
-		<< config.height << "-0x" << std::hex << std::setfill('0')
-		<< std::setw(8) << config.pixelFormat;
+	for (auto it = confs.begin(); it != confs.end(); ++it) {
+		StreamConfiguration &conf = *it;
+		auto sit = availableStreams.begin();
+
+		while (sit != availableStreams.end()) {
+			IPU3StreamProperties *props = &data->streamProps_[*sit];
+
+			if (!props->match(conf)) {
+				++sit;
+				continue;
+			}
+
+			/*
+			 * FIXME: Soraka: the maximum resolution reported by
+			 * both sensors (2592x1944 for ov5670 and 4224x3136 for
+			 * ov13858) are returned as default configurations but
+			 * they're not correctly processed by the ImgU.
+			 * Resolutions up tp 2560x1920 have been validated.
+			 *
+			 * \todo Clarify ImgU alignement requirements.
+			 */
+			conf.width = 2560;
+			conf.height = 1920;
+			conf.pixelFormat = V4L2_PIX_FMT_NV12;
+			conf.bufferCount = IPU3_BUFFER_COUNT;
+			configs[*sit] = conf;
+
+			LOG(IPU3, Debug)
+				<< "Stream " << props->name()
+				<< " format set to " << conf.width << "x"
+				<< conf.height << "-0x" << std::hex
+				<< std::setfill('0') << std::setw(8)
+				<< conf.pixelFormat;
+
+			/*
+			 * Once the stream has been assigned, remove it
+			 * from the list of available ones.
+			 */
+			availableStreams.erase(sit);
+			break;
+		}
+		if (sit == availableStreams.end()) {
+			LOG(IPU3, Error)
+				<< "Cannot satisfy the requested configuration";
+			return std::map<Stream *, StreamConfiguration> {};
+		}
+	}
 
 	return configs;
 }
diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
index d571b8b4ea83..a88784b28189 100644
--- a/src/libcamera/pipeline/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo.cpp
@@ -28,7 +28,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -86,7 +86,7 @@ PipelineHandlerUVC::~PipelineHandlerUVC()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerUVC::streamConfiguration(Camera *camera,
-					std::set<Stream *> &streams)
+					std::list<StreamConfiguration> &confs)
 {
 	UVCCameraData *data = cameraData(camera);
 
diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index e83416effad8..e36a58e70f8c 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -28,7 +28,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -86,7 +86,7 @@ PipelineHandlerVimc::~PipelineHandlerVimc()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerVimc::streamConfiguration(Camera *camera,
-					 std::set<Stream *> &streams)
+					 std::list<StreamConfiguration> &confs)
 {
 	VimcCameraData *data = cameraData(camera);
 	std::map<Stream *, StreamConfiguration> configs;
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 82070d364c03..2dc78d7f0b5e 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -183,18 +183,25 @@ PipelineHandler::~PipelineHandler()
 
 /**
  * \fn PipelineHandler::streamConfiguration()
- * \brief Retrieve a group of stream configurations for a specified camera
+ * \brief Retrieve the streams matching a configurations for a specified camera
  * \param[in] camera The camera to fetch default configuration from
- * \param[in] streams An array of streams to fetch information about
+ * \param[in] config The list of requested stream configurations
  *
- * Retrieve the species camera's default configuration for a specified group of
- * streams. The caller shall populate the \a streams array with the streams it
- * wish to fetch the configuration from. The map of streams and configuration
- * returned can then be examined by the caller to learn about the defualt
- * parameters for the specified streams.
+ * For each provided stream configuration request, retrieve a stream in the
+ * camera that satisfies it and return it with an associated default
+ * configuration.
+ *
+ * The caller shall populate the \a config array with the stream configurations
+ * it wishes to have satisfied, specifying the requested sizes, formats and the
+ * stream's intended usage. The pipeline handler retrieves a stream that matches
+ * the characteristics reported in the configuration and associates it a default
+ * configuration in the returned map.
+ *
+ * The returned map can then be examined by the caller to learn about the
+ * defualt parameters for the returned streams.
  *
  * The intended companion to this is \a configureStreams() which can be used to
- * change the group of streams parameters.
+ * change each stream parameters and have them applied in the Camera.
  *
  * \return A map of successfully retrieved streams and configurations or an
  * empty map on error.
