diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c
index 3816763f3a8c9d768619049fce77010e27e859d8..0c6cce7cfc30297473f0b622e281778df858a9d6 100644
--- a/lib/wp/endpoint.c
+++ b/lib/wp/endpoint.c
@@ -93,6 +93,7 @@ struct _WpEndpointPrivate
 {
   gchar *name;
   gchar media_class[40];
+  guint direction;
   GPtrArray *streams;
   GPtrArray *controls;
   GPtrArray *links;
@@ -104,6 +105,7 @@ enum {
   PROP_CORE,
   PROP_NAME,
   PROP_MEDIA_CLASS,
+  PROP_DIRECTION,
 };
 
 enum {
@@ -211,6 +213,9 @@ wp_endpoint_set_property (GObject * object, guint property_id,
     strncpy (priv->media_class, g_value_get_string (value),
         sizeof (priv->media_class) - 1);
     break;
+  case PROP_DIRECTION:
+    priv->direction = g_value_get_uint(value);
+    break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     break;
@@ -234,6 +239,9 @@ wp_endpoint_get_property (GObject * object, guint property_id, GValue * value,
   case PROP_MEDIA_CLASS:
     g_value_set_string (value, priv->media_class);
     break;
+  case PROP_DIRECTION:
+    g_value_set_uint (value, priv->direction);
+    break;
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     break;
@@ -281,6 +289,15 @@ wp_endpoint_class_init (WpEndpointClass * klass)
   signals[SIGNAL_NOTIFY_CONTROL_VALUE] = g_signal_new ("notify-control-value",
       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
       G_TYPE_NONE, 1, G_TYPE_UINT);
+
+  /**
+   * WpEndpoint::direction:
+   * The direction of the endpoint: input = 0, output = 1.
+   */
+  g_object_class_install_property (object_class, PROP_DIRECTION,
+      g_param_spec_uint ("direction", "direction",
+          "The direction of the endpoint", 0, 1, 0,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 }
 
 /**
@@ -465,6 +482,17 @@ wp_endpoint_get_media_class (WpEndpoint * self)
   return priv->media_class;
 }
 
+guint
+wp_endpoint_get_direction (WpEndpoint * self)
+{
+  WpEndpointPrivate *priv;
+
+  g_return_val_if_fail (WP_IS_ENDPOINT (self), -1);
+
+  priv = wp_endpoint_get_instance_private (self);
+  return priv->direction;
+}
+
 /**
  * wp_endpoint_register_stream:
  * @self: the endpoint
diff --git a/lib/wp/endpoint.h b/lib/wp/endpoint.h
index 2ef688b65ffc55e1c5b7163f8cc97eb519b62c63..b41cc33f72f08afeda3bd0302122c152ab80ff7b 100644
--- a/lib/wp/endpoint.h
+++ b/lib/wp/endpoint.h
@@ -48,6 +48,7 @@ GPtrArray * wp_endpoint_find (WpCore * core, const gchar * media_class_lookup);
 WpCore *wp_endpoint_get_core (WpEndpoint * self);
 const gchar * wp_endpoint_get_name (WpEndpoint * self);
 const gchar * wp_endpoint_get_media_class (WpEndpoint * self);
+guint wp_endpoint_get_direction (WpEndpoint * self);
 
 void wp_endpoint_register_stream (WpEndpoint * self, GVariant * stream);
 GVariant * wp_endpoint_get_stream (WpEndpoint * self, guint32 stream_id);
diff --git a/modules/module-pipewire/simple-endpoint.c b/modules/module-pipewire/simple-endpoint.c
index e644a50db7fed6a95f5f7b272101d437fb333072..c50a512319ac1cc13795c4ae0cf5d68f9b2118bd 100644
--- a/modules/module-pipewire/simple-endpoint.c
+++ b/modules/module-pipewire/simple-endpoint.c
@@ -42,9 +42,6 @@ struct _WpPipewireSimpleEndpoint
   /* Handler */
   gulong proxy_node_done_handler_id;
 
-  /* Direction */
-  enum pw_direction direction;
-
   /* Proxies */
   WpProxyNode *proxy_node;
   struct spa_hook node_proxy_listener;
@@ -58,7 +55,6 @@ struct _WpPipewireSimpleEndpoint
 enum {
   PROP_0,
   PROP_GLOBAL_ID,
-  PROP_DIRECTION,
   PROP_ROLE,
   PROP_CREATION_TIME,
   PROP_TARGET,
@@ -231,6 +227,7 @@ on_port_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
 static void
 emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
 {
+  enum pw_direction direction = wp_endpoint_get_direction (WP_ENDPOINT (self));
   struct pw_node_proxy* node_proxy = NULL;
   struct spa_audio_info_raw format = { 0, };
   struct spa_pod *param;
@@ -253,7 +250,7 @@ emit_endpoint_ports(WpPipewireSimpleEndpoint *self)
   param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
   param = spa_pod_builder_add_object(&pod_builder,
       SPA_TYPE_OBJECT_ParamPortConfig,  SPA_PARAM_PortConfig,
-      SPA_PARAM_PORT_CONFIG_direction,  SPA_POD_Id(self->direction),
+      SPA_PARAM_PORT_CONFIG_direction,  SPA_POD_Id(direction),
       SPA_PARAM_PORT_CONFIG_mode,       SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
       SPA_PARAM_PORT_CONFIG_format,     SPA_POD_Pod(param));
 
@@ -400,9 +397,6 @@ simple_endpoint_set_property (GObject * object, guint property_id,
   case PROP_GLOBAL_ID:
     self->global_id = g_value_get_uint(value);
     break;
-  case PROP_DIRECTION:
-    self->direction = g_value_get_uint(value);
-    break;
   case PROP_ROLE:
     g_free (self->role);
     self->role = g_value_dup_string (value);
@@ -427,9 +421,6 @@ simple_endpoint_get_property (GObject * object, guint property_id,
   case PROP_GLOBAL_ID:
     g_value_set_uint (value, self->global_id);
     break;
-  case PROP_DIRECTION:
-    g_value_set_uint (value, self->direction);
-    break;
   case PROP_ROLE:
     g_value_set_string (value, self->role);
     break;
@@ -559,10 +550,6 @@ simple_endpoint_class_init (WpPipewireSimpleEndpointClass * klass)
       g_param_spec_uint ("global-id", "global-id",
           "The global Id this endpoint refers to", 0, G_MAXUINT, 0,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (object_class, PROP_DIRECTION,
-      g_param_spec_uint ("direction", "direction",
-          "The direction of the simple endpoint", 0, 1, 0,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_ROLE,
       g_param_spec_string ("role", "role", "The role of the wrapped node", NULL,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
@@ -581,8 +568,8 @@ simple_endpoint_factory (WpFactory * factory, GType type,
 {
   g_autoptr (WpCore) core = NULL;
   const gchar *name, *media_class;
-  guint global_id;
   guint direction;
+  guint global_id;
 
   /* Make sure the type is correct */
   g_return_if_fail (type == WP_TYPE_ENDPOINT);
@@ -596,17 +583,17 @@ simple_endpoint_factory (WpFactory * factory, GType type,
       return;
   if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
       return;
-  if (!g_variant_lookup (properties, "global-id", "u", &global_id))
-      return;
   if (!g_variant_lookup (properties, "direction", "u", &direction))
       return;
+  if (!g_variant_lookup (properties, "global-id", "u", &global_id))
+      return;
 
   g_async_initable_new_async (
       simple_endpoint_get_type (), G_PRIORITY_DEFAULT, NULL, ready, user_data,
       "core", core,
       "name", name,
       "media-class", media_class,
-      "global-id", global_id,
       "direction", direction,
+      "global-id", global_id,
       NULL);
 }
diff --git a/modules/module-pw-alsa-udev.c b/modules/module-pw-alsa-udev.c
index ff3740077b33df402a00308540cbaa6d2f88e0d3..48cd8d25d217ffd9fa46bff549805cfc9bd85b2c 100644
--- a/modules/module-pw-alsa-udev.c
+++ b/modules/module-pw-alsa-udev.c
@@ -96,6 +96,7 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
   const struct spa_dict *props = p;
   g_autoptr (WpCore) core = wp_module_get_core (impl->module);
   const gchar *media_class, *name;
+  enum pw_direction direction;
   GVariantBuilder b;
   g_autoptr (GVariant) endpoint_props = NULL;
 
@@ -120,12 +121,24 @@ on_node_added(WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
   if (g_str_has_prefix (name, "api.bluez5"))
     return;
 
+  /* Get the direction */
+  if (g_str_has_prefix (media_class, "Audio/Sink")) {
+    direction = PW_DIRECTION_INPUT;
+  } else if (g_str_has_prefix (media_class, "Audio/Source")) {
+    direction = PW_DIRECTION_OUTPUT;
+  } else {
+    g_critical ("failed to parse direction");
+    return;
+  }
+
   /* Set the properties */
   g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
   g_variant_builder_add (&b, "{sv}",
       "name", g_variant_new_string (name));
   g_variant_builder_add (&b, "{sv}",
       "media-class", g_variant_new_string (media_class));
+  g_variant_builder_add (&b, "{sv}",
+      "direction", g_variant_new_uint32 (direction));
   g_variant_builder_add (&b, "{sv}",
       "global-id", g_variant_new_uint32 (id));
   g_variant_builder_add (&b, "{sv}",
diff --git a/modules/module-pw-audio-client.c b/modules/module-pw-audio-client.c
index 630ff1d9e323e52dddf1530616a0e620261db538..379fe04adddf46b4cc77ee3c44099fea7007ac38 100644
--- a/modules/module-pw-audio-client.c
+++ b/modules/module-pw-audio-client.c
@@ -94,10 +94,10 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
       g_variant_new_take_string (g_strdup_printf ("Stream %u", id)));
   g_variant_builder_add (&b, "{sv}",
       "media-class", g_variant_new_string (media_class));
-  g_variant_builder_add (&b, "{sv}",
-      "global-id", g_variant_new_uint32 (id));
   g_variant_builder_add (&b, "{sv}",
       "direction", g_variant_new_uint32 (direction));
+  g_variant_builder_add (&b, "{sv}",
+      "global-id", g_variant_new_uint32 (id));
   endpoint_props = g_variant_builder_end (&b);
 
   /* Create the endpoint async */
diff --git a/modules/module-pw-audio-softdsp-endpoint.c b/modules/module-pw-audio-softdsp-endpoint.c
index 263962a2ae1739912b78db8c9459ba7b2a02b1b9..2d8f1c89d6b5d9bd96d6d8bc745c877168fbd8d1 100644
--- a/modules/module-pw-audio-softdsp-endpoint.c
+++ b/modules/module-pw-audio-softdsp-endpoint.c
@@ -42,9 +42,6 @@ struct _WpPwAudioSoftdspEndpoint
   GTask *init_task;
   gboolean init_abort;
 
-  /* Direction */
-  enum pw_direction direction;
-
   /* Audio Streams */
   WpAudioStream *adapter;
   GPtrArray *converters;
@@ -162,6 +159,7 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res,
     gpointer data)
 {
   WpPwAudioSoftdspEndpoint *self = data;
+  enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self));
   g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
   g_autofree gchar *name = NULL;
   const struct pw_node_info *adapter_info = NULL;
@@ -193,8 +191,8 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res,
   /* Create the audio converters */
   g_variant_iter_init (&iter, self->streams);
   for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) {
-    wp_audio_convert_new (WP_ENDPOINT(self), i, stream, self->direction,
-        adapter_info, on_audio_convert_created, self);
+    wp_audio_convert_new (WP_ENDPOINT(self), i, stream, direction, adapter_info,
+        on_audio_convert_created, self);
 
     /* Register the stream */
     g_variant_dict_init (&d, NULL);
@@ -316,24 +314,16 @@ wp_endpoint_init_async (GAsyncInitable *initable, int io_priority,
     GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
 {
   WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (initable);
+  enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self));
   g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
-  const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self));
   GVariantDict d;
 
   /* Create the async task */
   self->init_task = g_task_new (initable, cancellable, callback, data);
 
-  /* Set the direction */
-  if (g_str_has_suffix (media_class, "Source"))
-    self->direction = PW_DIRECTION_OUTPUT;
-  else if (g_str_has_suffix (media_class, "Sink"))
-    self->direction = PW_DIRECTION_INPUT;
-  else
-    g_critical ("failed to parse direction");
-
   /* Create the adapter proxy */
   wp_audio_adapter_new (WP_ENDPOINT(self), WP_STREAM_ID_NONE, "master",
-      self->direction, self->global_id, FALSE, on_audio_adapter_created, self);
+      direction, self->global_id, FALSE, on_audio_adapter_created, self);
 
   /* Register the selected control */
   self->selected = FALSE;
@@ -401,6 +391,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
 {
   g_autoptr (WpCore) core = NULL;
   const gchar *name, *media_class;
+  guint direction;
   guint global_id;
   g_autoptr (GVariant) streams = NULL;
 
@@ -416,6 +407,8 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
       return;
   if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
       return;
+  if (!g_variant_lookup (properties, "direction", "u", &direction))
+      return;
   if (!g_variant_lookup (properties, "global-id", "u", &global_id))
       return;
   if (!(streams = g_variant_lookup_value (properties, "streams",
@@ -428,6 +421,7 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties,
       "core", core,
       "name", name,
       "media-class", media_class,
+      "direction", direction,
       "global-id", global_id,
       "streams", streams,
       NULL);
diff --git a/modules/module-pw-bluez.c b/modules/module-pw-bluez.c
index 89a77ea9007388e589ad2aae691f0cf5c029c4e2..6b3bf526a7775aec038dc048590dfa93e34894a7 100644
--- a/modules/module-pw-bluez.c
+++ b/modules/module-pw-bluez.c
@@ -131,10 +131,10 @@ on_node_added (WpRemotePipewire *rp, guint id, gconstpointer p, gpointer d)
       g_variant_new_take_string (g_strdup_printf ("Stream %u", id)));
   g_variant_builder_add (&b, "{sv}",
       "media-class", g_variant_new_string (media_class));
-  g_variant_builder_add (&b, "{sv}",
-      "global-id", g_variant_new_uint32 (id));
   g_variant_builder_add (&b, "{sv}",
       "direction", g_variant_new_uint32 (direction));
+  g_variant_builder_add (&b, "{sv}",
+      "global-id", g_variant_new_uint32 (id));
   endpoint_props = g_variant_builder_end (&b);
 
   /* Create the endpoint async */