diff --git a/RELEASE-NOTES-next b/RELEASE-NOTES-next
index 4f45b145..45c92721 100644
--- a/RELEASE-NOTES-next
+++ b/RELEASE-NOTES-next
@@ -17,6 +17,8 @@ strongly encouraged to upgrade.
   • i3bar: use first bar config by default
   • i3-dump-log -f now uses UNIX sockets instead of pthreads. The UNIX socket approach
     should be more reliable and also more portable.
+  • Allow for_window to match against WM_CLIENT_MACHINE
+  • Add %machine placeholder (WM_CLIENT_MACHINE) to title_format
 
  ┌────────────────────────────┐
  │ Bugfixes                   │
diff --git a/docs/ipc b/docs/ipc
index 8377795d..e130094c 100644
--- a/docs/ipc
+++ b/docs/ipc
@@ -362,7 +362,8 @@ window (integer)::
 	X11-related tools display (usually in hex).
 window_properties (map)::
 	This optional field contains all available X11 window properties from the
-	following list: *title*, *instance*, *class*, *window_role* and *transient_for*.
+	following list: *title*, *instance*, *class*, *window_role*, *machine*
+	and *transient_for*.
 window_type (string)::
 	The window type (_NET_WM_WINDOW_TYPE). Possible values are undefined, normal,
 	dialog, utility, toolbar, splash, menu, dropdown_menu, popup_menu, tooltip and
diff --git a/docs/layout-saving b/docs/layout-saving
index 4f0ffccf..380ffff8 100644
--- a/docs/layout-saving
+++ b/docs/layout-saving
@@ -185,9 +185,9 @@ Therefore, if you just start Emacs via dmenu, it will not get swallowed by that
 container. Only if you start Emacs with the proper instance name (+emacs24
 --name notmuch+), it will get swallowed.
 
-You can match on "class", "instance", "window_role" and "title". All values are
-case-sensitive regular expressions (PCRE). Use +xprop(1)+ and click into a
-window to see its properties:
+You can match on "class", "instance", "window_role", "title" and "machine". All
+values are case-sensitive regular expressions (PCRE). Use +xprop(1)+ and click
+into a window to see its properties:
 
 --------------------------------------------------------------------------------
 $ xprop
diff --git a/docs/userguide b/docs/userguide
index 37343df9..a727c040 100644
--- a/docs/userguide
+++ b/docs/userguide
@@ -1896,6 +1896,10 @@ window_type::
 	Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
 	+normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
 	+popup_menu+, +tooltip+ and +notification+.
+machine::
+	Compares the name of the machine the client window is running on
+	(WM_CLIENT_MACHINE). Usually, it is equal to the hostname of the local
+	machine, but it may differ if remote X11 apps are used.
 id::
 	Compares the X11 window ID, which you can get via +xwininfo+ for example.
 title::
@@ -1933,9 +1937,9 @@ tiling_from::
 	tiling are matched. With "user", only windows that the user made tiling
 	are matched.
 
-The criteria +class+, +instance+, +role+, +title+, +workspace+ and +mark+ are
-actually regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc perlre+ for
-information on how to use them.
+The criteria +class+, +instance+, +role+, +title+, +workspace+, +machine+ and
++mark+ are actually regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc
+perlre+ for information on how to use them.
 
 [[exec]]
 === Executing applications (exec)
@@ -2584,6 +2588,9 @@ and the following placeholders which will be replaced:
 +%instance+::
     The X11 window instance (first part of WM_CLASS). This corresponds to the
     +instance+ criterion, see <<command_criteria>>.
++%machine+::
+    The X11 name of the machine (WM_CLIENT_MACHINE). This corresponds to the
+    +machine+ criterion, see <<command_criteria>>.
 
 Using the <<for_window>> directive, you can set the title format for any window
 based on <<command_criteria>>.
diff --git a/include/data.h b/include/data.h
index e411129f..1d47af64 100644
--- a/include/data.h
+++ b/include/data.h
@@ -414,6 +414,9 @@ struct Window {
      * for_window. */
     char *role;
 
+    /** WM_CLIENT_MACHINE of the window */
+    char *machine;
+
     /** Flag to force re-rendering the decoration upon changes */
     bool name_x_changed;
 
@@ -500,6 +503,7 @@ struct Match {
     struct regex *mark;
     struct regex *window_role;
     struct regex *workspace;
+    struct regex *machine;
     xcb_atom_t window_type;
     enum {
         U_DONTCHECK = -1,
diff --git a/include/window.h b/include/window.h
index 6673e835..858bf0cd 100644
--- a/include/window.h
+++ b/include/window.h
@@ -95,3 +95,9 @@ void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop, bool *ur
  *
  */
 void window_update_motif_hints(i3Window *win, xcb_get_property_reply_t *prop, border_style_t *motif_border_style);
+
+/**
+ * Updates the WM_CLIENT_MACHINE
+ *
+ */
+void window_update_machine(i3Window *win, xcb_get_property_reply_t *prop);
diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec
index 4db81680..6a15ad19 100644
--- a/parser-specs/commands.spec
+++ b/parser-specs/commands.spec
@@ -54,6 +54,7 @@ state CRITERIA:
   ctype = 'title'       -> CRITERION
   ctype = 'urgent'      -> CRITERION
   ctype = 'workspace'   -> CRITERION
+  ctype = 'machine'     -> CRITERION
   ctype = 'tiling', 'floating'
       -> call cmd_criteria_add($ctype, NULL); CRITERIA
   ']' -> call cmd_criteria_match_windows(); INITIAL
diff --git a/parser-specs/config.spec b/parser-specs/config.spec
index bb9e226e..7d7b9989 100644
--- a/parser-specs/config.spec
+++ b/parser-specs/config.spec
@@ -191,6 +191,7 @@ state CRITERIA:
   ctype = 'title'         -> CRITERION
   ctype = 'urgent'        -> CRITERION
   ctype = 'workspace'     -> CRITERION
+  ctype = 'machine'     -> CRITERION
   ctype = 'floating_from' -> CRITERION_FROM
   ctype = 'tiling_from'   -> CRITERION_FROM
   ctype = 'tiling', 'floating'
diff --git a/src/con.c b/src/con.c
index 1f0dbed3..9f0eb7ad 100644
--- a/src/con.c
+++ b/src/con.c
@@ -2304,20 +2304,25 @@ i3String *con_parse_title_format(Con *con) {
     char *title;
     char *class;
     char *instance;
+    char *machine;
     if (win == NULL) {
         title = pango_escape_markup(con_get_tree_representation(con));
         class = sstrdup("i3-frame");
         instance = sstrdup("i3-frame");
+        machine = sstrdup("");
     } else {
         title = pango_escape_markup(sstrdup((win->name == NULL) ? "" : i3string_as_utf8(win->name)));
         class = pango_escape_markup(sstrdup((win->class_class == NULL) ? "" : win->class_class));
         instance = pango_escape_markup(sstrdup((win->class_instance == NULL) ? "" : win->class_instance));
+        machine = pango_escape_markup(sstrdup((win->machine == NULL) ? "" : win->machine));
     }
 
     placeholder_t placeholders[] = {
         {.name = "%title", .value = title},
         {.name = "%class", .value = class},
-        {.name = "%instance", .value = instance}};
+        {.name = "%instance", .value = instance},
+        {.name = "%machine", .value = machine},
+    };
     const size_t num = sizeof(placeholders) / sizeof(placeholder_t);
 
     char *formatted_str = format_placeholders(con->title_format, &placeholders[0], num);
diff --git a/src/handlers.c b/src/handlers.c
index eba5fe29..fe967773 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -1086,6 +1086,16 @@ static bool handle_class_change(Con *con, xcb_get_property_reply_t *prop) {
     return true;
 }
 
+/*
+ * Handles the WM_CLIENT_MACHINE property for assignments and criteria selection.
+ *
+ */
+static bool handle_machine_change(Con *con, xcb_get_property_reply_t *prop) {
+    window_update_machine(con->window, prop);
+    con = remanage_window(con);
+    return true;
+}
+
 /*
  * Handles the _MOTIF_WM_HINTS property of specifing window deocration settings.
  *
@@ -1197,6 +1207,7 @@ static struct property_handler_t property_handlers[] = {
     {0, UINT_MAX, handle_strut_partial_change},
     {0, UINT_MAX, handle_window_type},
     {0, UINT_MAX, handle_i3_floating},
+    {0, 128, handle_machine_change},
     {0, 5 * sizeof(uint64_t), handle_motif_hints_change}};
 #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
 
@@ -1219,7 +1230,8 @@ void property_handlers_init(void) {
     property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
     property_handlers[9].atom = A__NET_WM_WINDOW_TYPE;
     property_handlers[10].atom = A_I3_FLOATING_WINDOW;
-    property_handlers[11].atom = A__MOTIF_WM_HINTS;
+    property_handlers[11].atom = XCB_ATOM_WM_CLIENT_MACHINE;
+    property_handlers[12].atom = A__MOTIF_WM_HINTS;
 }
 
 static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
diff --git a/src/ipc.c b/src/ipc.c
index d69ecb6e..1ebe15d0 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -557,6 +557,7 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
         DUMP_PROPERTY("class", class_class);
         DUMP_PROPERTY("instance", class_instance);
         DUMP_PROPERTY("window_role", role);
+        DUMP_PROPERTY("machine", machine);
 
         if (con->window->name != NULL) {
             ystr("title");
@@ -646,6 +647,7 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
         DUMP_REGEX(instance);
         DUMP_REGEX(window_role);
         DUMP_REGEX(title);
+        DUMP_REGEX(machine);
 
 #undef DUMP_REGEX
         y(map_close);
diff --git a/src/load_layout.c b/src/load_layout.c
index bb91ffa4..3d8033e8 100644
--- a/src/load_layout.c
+++ b/src/load_layout.c
@@ -285,6 +285,9 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) {
         } else if (strcasecmp(last_key, "title") == 0) {
             current_swallow->title = regex_new(sval);
             swallow_is_empty = false;
+        } else if (strcasecmp(last_key, "machine") == 0) {
+            current_swallow->machine = regex_new(sval);
+            swallow_is_empty = false;
         } else {
             ELOG("swallow key %s unknown\n", last_key);
         }
diff --git a/src/manage.c b/src/manage.c
index da23ab3e..8ea820de 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -116,7 +116,8 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
         utf8_title_cookie, title_cookie,
         class_cookie, leader_cookie, transient_cookie,
         role_cookie, startup_id_cookie, wm_hints_cookie,
-        wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie, wm_desktop_cookie;
+        wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie, wm_desktop_cookie,
+        wm_machine_cookie;
 
     geomc = xcb_get_geometry(conn, d);
 
@@ -189,6 +190,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t));
     wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX);
     wm_desktop_cookie = GET_PROPERTY(A__NET_WM_DESKTOP, UINT32_MAX);
+    wm_machine_cookie = GET_PROPERTY(XCB_ATOM_WM_CLIENT_MACHINE, UINT32_MAX);
 
     i3Window *cwindow = scalloc(1, sizeof(i3Window));
     cwindow->id = window;
@@ -211,6 +213,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     border_style_t motif_border_style = BS_NORMAL;
     window_update_motif_hints(cwindow, xcb_get_property_reply(conn, motif_wm_hints_cookie, NULL), &motif_border_style);
     window_update_normal_hints(cwindow, xcb_get_property_reply(conn, wm_normal_hints_cookie, NULL), geom);
+    window_update_machine(cwindow, xcb_get_property_reply(conn, wm_machine_cookie, NULL));
     xcb_get_property_reply_t *type_reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
     xcb_get_property_reply_t *state_reply = xcb_get_property_reply(conn, state_cookie, NULL);
 
diff --git a/src/match.c b/src/match.c
index 6ac312e5..65646f9e 100644
--- a/src/match.c
+++ b/src/match.c
@@ -47,6 +47,7 @@ bool match_is_empty(Match *match) {
             match->instance == NULL &&
             match->window_role == NULL &&
             match->workspace == NULL &&
+            match->machine == NULL &&
             match->urgent == U_DONTCHECK &&
             match->id == XCB_NONE &&
             match->window_type == UINT32_MAX &&
@@ -130,6 +131,8 @@ bool match_matches_window(Match *match, i3Window *window) {
         }
     }
 
+    CHECK_WINDOW_FIELD(machine, machine, str);
+
     Con *con = NULL;
     if (match->urgent == U_LATEST) {
         /* if the window isn't urgent, no sense in searching */
@@ -273,6 +276,7 @@ void match_free(Match *match) {
     regex_free(match->mark);
     regex_free(match->window_role);
     regex_free(match->workspace);
+    regex_free(match->machine);
 }
 
 /*
@@ -390,6 +394,12 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
         return;
     }
 
+    if (strcmp(ctype, "machine") == 0) {
+        regex_free(match->machine);
+        match->machine = regex_new(cvalue);
+        return;
+    }
+
     if (strcmp(ctype, "tiling") == 0) {
         match->window_mode = WM_TILING;
         return;
diff --git a/src/restore_layout.c b/src/restore_layout.c
index c51bfcbe..78f0e097 100644
--- a/src/restore_layout.c
+++ b/src/restore_layout.c
@@ -153,6 +153,7 @@ static void update_placeholder_contents(placeholder_state *state) {
         APPEND_REGEX(instance);
         APPEND_REGEX(window_role);
         APPEND_REGEX(title);
+        APPEND_REGEX(machine);
 
         if (serialized == NULL) {
             DLOG("This swallows specification is not serializable?!\n");
diff --git a/src/window.c b/src/window.c
index bee3fa66..2c2f6c0a 100644
--- a/src/window.c
+++ b/src/window.c
@@ -466,3 +466,21 @@ void window_update_motif_hints(i3Window *win, xcb_get_property_reply_t *prop, bo
 #undef MWM_DECOR_BORDER
 #undef MWM_DECOR_TITLE
 }
+
+/*
+ * Updates the WM_CLIENT_MACHINE
+ *
+ */
+void window_update_machine(i3Window *win, xcb_get_property_reply_t *prop) {
+    if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
+        DLOG("WM_CLIENT_MACHINE not set.\n");
+        FREE(prop);
+        return;
+    }
+
+    FREE(win->machine);
+    win->machine = sstrndup((char *)xcb_get_property_value(prop), xcb_get_property_value_length(prop));
+    LOG("WM_CLIENT_MACHINE changed to \"%s\"\n", win->machine);
+
+    free(prop);
+}