diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 3f4d1e28208b..25901303b97d 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -9,6 +9,7 @@ libcamera_api = files([
     'request.h',
     'signal.h',
     'stream.h',
+    'stream_usages.h',
     'timer.h',
 ])
 
diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h
index 970c479627fa..afcc4ff08923 100644
--- a/include/libcamera/stream.h
+++ b/include/libcamera/stream.h
@@ -7,7 +7,10 @@
 #ifndef __LIBCAMERA_STREAM_H__
 #define __LIBCAMERA_STREAM_H__
 
+#include <forward_list>
+
 #include <libcamera/buffer.h>
+#include <libcamera/stream_usages.h>
 
 namespace libcamera {
 
@@ -19,6 +22,10 @@ struct StreamConfiguration {
 	unsigned int pixelFormat;
 
 	unsigned int bufferCount;
+
+	std::forward_list<enum StreamUsage> hints;
+
+	bool supports(const enum StreamUsage &usage) const;
 };
 
 class Stream final
diff --git a/include/libcamera/stream_usages.h b/include/libcamera/stream_usages.h
new file mode 100644
index 000000000000..9f7358954181
--- /dev/null
+++ b/include/libcamera/stream_usages.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * stream_usages.h - Definition of stream usage hints
+ */
+#ifndef __LIBCAMERA_STREAM_USAGES_H__
+#define __LIBCAMERA_STREAM_USAGES_H__
+
+namespace libcamera {
+
+enum StreamUsage {
+	VIEWFINDER,
+	VIDEO_RECORDING,
+	STILL_CAPTURE,
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_STREAM_USAGES_H__ */
diff --git a/src/libcamera/include/stream_properties.h b/src/libcamera/include/stream_properties.h
new file mode 100644
index 000000000000..ced8bb931bf6
--- /dev/null
+++ b/src/libcamera/include/stream_properties.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * stream_properties.h - Properties associated with a camera stream
+ */
+
+#ifndef __LIBCAMERA_STREAM_PROPERTIES_H__
+#define __LIBCAMERA_STREAM_PROPERTIES_H__
+
+#include <forward_list>
+#include <string>
+
+#include <libcamera/stream.h>
+#include <libcamera/stream_usages.h>
+
+#include "formats.h"
+
+namespace libcamera {
+
+class StreamProperties {
+public:
+	virtual ~StreamProperties() { }
+
+	void addUsage(const enum StreamUsage &usage);
+	void addFormat(unsigned int pixfmt, std::vector<SizeRange> sizes);
+
+	const std::string &name() const { return name_; }
+	void setName(const std::string &name);
+
+	virtual bool match(const StreamConfiguration &config) const;
+
+private:
+	std::forward_list<enum StreamUsage> usages_;
+	FormatEnum formats_;
+	std::string name_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_STREAM_USAGES_H__ */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 4433abfceca3..b00a34919c2c 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -16,6 +16,7 @@ libcamera_sources = files([
     'request.cpp',
     'signal.cpp',
     'stream.cpp',
+    'stream_properties.cpp',
     'timer.cpp',
     'v4l2_device.cpp',
     'v4l2_subdevice.cpp',
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 69b40aa0026b..46479944a4da 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -14,12 +14,14 @@
 #include <libcamera/camera.h>
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
+#include <libcamera/stream_usages.h>
 
 #include "device_enumerator.h"
 #include "geometry.h"
 #include "log.h"
 #include "media_device.h"
 #include "pipeline_handler.h"
+#include "stream_properties.h"
 #include "utils.h"
 #include "v4l2_device.h"
 #include "v4l2_subdevice.h"
@@ -28,6 +30,17 @@ namespace libcamera {
 
 LOG_DEFINE_CATEGORY(IPU3)
 
+class IPU3StreamProperties : public StreamProperties
+{
+public:
+	static constexpr unsigned int IMGU_VIDEO_MODE = 0;
+	static constexpr unsigned int IMGU_STILL_MODE = 1;
+
+	~IPU3StreamProperties() { }
+
+	unsigned int pipelineMode;
+};
+
 static int mediaBusToCIO2Format(unsigned int code)
 {
 	switch (code) {
@@ -222,6 +235,7 @@ private:
 
 		Stream outStream_;
 		Stream vfStream_;
+		std::map<Stream *, IPU3StreamProperties> streamProps_;
 
 		/* Absolute miniumum and maximum sizes. */
 		SizeRange sizes_;
@@ -811,6 +825,37 @@ int PipelineHandlerIPU3::registerCameras()
 		data->imgu_->viewfinder_->bufferReady.connect(data.get(),
 					&IPU3CameraData::imguCaptureBufferReady);
 
+
+		/*
+		 * Prepare the enumerations of formats supported by the
+		 * streams.
+		 *
+		 * \todo: As of now, only support continous size ranges.
+		 */
+		SizeRange &cio2MaxSize = cio2->maxSizes_.second;
+		SizeRange ipu3StreamSizes(1, 1, cio2MaxSize.maxWidth,
+					  cio2MaxSize.maxHeight);
+
+		/* Fill in the properties for each supported stream. */
+		IPU3StreamProperties outputStreamProps;
+		outputStreamProps.setName("output");
+		outputStreamProps.addUsage(STILL_CAPTURE);
+		outputStreamProps.addFormat(V4L2_PIX_FMT_NV12,
+					    { ipu3StreamSizes } );
+		outputStreamProps.pipelineMode =
+			IPU3StreamProperties::IMGU_STILL_MODE;
+		data->streamProps_[&data->outStream_] = outputStreamProps;
+
+		IPU3StreamProperties viewfinderStreamProps;
+		viewfinderStreamProps.setName("viewfinder");
+		viewfinderStreamProps.addUsage(VIEWFINDER);
+		viewfinderStreamProps.addUsage(VIDEO_RECORDING);
+		viewfinderStreamProps.addFormat(V4L2_PIX_FMT_NV12,
+						{ ipu3StreamSizes } );
+		outputStreamProps.pipelineMode =
+			IPU3StreamProperties::IMGU_VIDEO_MODE;
+		data->streamProps_[&data->vfStream_] = viewfinderStreamProps;
+
 		/* Create and register the Camera instance. */
 		std::string cameraName = cio2->name() + " "
 				       + std::to_string(id);
diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp
index c4943c91b2e6..7b8d6ac4f895 100644
--- a/src/libcamera/stream.cpp
+++ b/src/libcamera/stream.cpp
@@ -60,6 +60,31 @@ namespace libcamera {
  * \brief Requested number of buffers to allocate for the stream
  */
 
+/**
+ * \var StreamConfiguration::hints
+ * \brief List of intended stream usages
+ *
+ * This field represents a list of intended stream usage hints. It is set
+ * by applications when requesting the stream's default configurations with
+ * Camera::streamConfiguration() method.
+ */
+
+/**
+ * \brief Verify if a stream configuration supports a \a usage
+ * \param[in] usage The stream usage to verify
+ *
+ * \return True if the usage is supported, false otherwise
+ */
+bool StreamConfiguration::supports(const enum StreamUsage &usage) const
+{
+	for (const enum StreamUsage &hint : hints) {
+		if (hint == usage)
+			return true;
+	}
+
+	return false;
+}
+
 /**
  * \class Stream
  * \brief Video stream for a camera
diff --git a/src/libcamera/stream_properties.cpp b/src/libcamera/stream_properties.cpp
new file mode 100644
index 000000000000..582b314b7bb6
--- /dev/null
+++ b/src/libcamera/stream_properties.cpp
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * stream_properties.cpp - Properties associated with a camera stream
+ */
+
+#include <libcamera/stream.h>
+
+#include "log.h"
+#include "stream_properties.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(PROPS)
+
+/**
+ * \class StreamProperties
+ * \brief Collect a stream characteristics and matches them against a
+ * requested stream configuration
+ *
+ * The StreamProperties class collects all the informations related to a
+ * Stream capabilities, including its name, the list of supported formats and
+ * sizes and the list of intended usages of the streams.
+ *
+ * Streams are created by pipeline handlers, and their static properties are
+ * represented by instances of this class, which pipeline handlers should
+ * internally associate with each of its streams.
+ *
+ * The stream properties can be matched against a requested stream
+ * configuration, and this operations is usually performed by pipeline
+ * handlers trying to satisfy an application request at
+ * PipelineHander::streamConfiguration() time, where a list of
+ * StreamConfiguration instances gets associated with a list of Streams.
+ *
+ * Pipeline handlers are free to sub-class StreamProperties to extend them
+ * and add platform-specific informations, as StreamProperties are not exposed
+ * to applications nor in the public library interface (for this reason, there
+ * is not direct dependencies between this class and the Stream one, which is
+ * publicly exposed and directly used by applications). The additional
+ * platform specific informations shall be used in the stream matching procedure
+ * or to store pipeline specific configuration parameters associated with a
+ * stream.
+ */
+
+/**
+ * \brief Add a usage hint to the stream property
+ * \param[in] usage The usage hint
+ */
+void StreamProperties::addUsage(const enum StreamUsage &usage)
+{
+	usages_.push_front(usage);
+}
+
+/**
+ * \brief Add a list of supported sizes associated with a pixel format
+ * \param[in] pixfmt The pixel format
+ * \param[in] sizes The list of size ranges
+ */
+void StreamProperties::addFormat(unsigned int pixfmt,
+				 std::vector<SizeRange> sizes)
+{
+	if (formats_.find(pixfmt) != formats_.end())
+		LOG(PROPS, Error) << "Overwriting sizes associated with format "
+				  << pixfmt;
+
+	formats_[pixfmt] = sizes;
+}
+
+/**
+ * \fn StreamProperties::name()
+ * \brief Retrieve the stream name
+ *
+ * \return The stream name
+ */
+
+/**
+ * \brief Set the stream name
+ * \param[in] name The stream name
+ */
+void StreamProperties::setName(const std::string &name)
+{
+	name_ = name;
+}
+
+/**
+ * \brief Compare the properties of a stream with a stream configuration request
+ * \param[in] config The requested stream configuration
+ *
+ * This helper method compares the properties of a stream with a stream
+ * requested configuration. Its intended users are pipeline handlers that
+ * receive stream configurations and try to match them with a stream that
+ * satisfies the request parameters.
+ *
+ * A StreamProperties satisfies the requested \a config when:
+ * 1) The requested pixel format is listed in the property's formats map;
+ * 2) The requested sizes are included in the supported size intervals list in
+ * the property's formats map;
+ * 3) At least one of the requested usage hints is reported in the property's
+ * list of intended usages;
+ *
+ * If all the above criteria as satisfied, the helper return true and the
+ * stream associated with the property matches the requested configuration.
+ *
+ * \return True if the stream's properties satisfy the requested configuration,
+ * false otherwise
+ */
+bool StreamProperties::match(const StreamConfiguration &config) const
+{
+	/* \todo: as a proof of concept, right now only match on 'hints'. */
+	for (const enum StreamUsage &usage : usages_) {
+		for (const enum StreamUsage &hint : config.hints) {
+			if (usage == hint)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+} /* namespace libcamera */
