Is there a way to set different post templates for parent posts and child posts in the same post type?

Simplest way is to use single_template filter hook (one of the {$type}_template hooks).

It is fired by WordPress to filter the template file found for singular post requests.

add_filter('single_template', function($template) {

  $queried = get_queried_object();

  if ( $queried->post_type === 'clients_projects' ) { // only for this CPT
    // file name per OP requirements
    $file="clients_projects_";
    $file .= $queried->post_parent ? 'child' : 'parent';

    // using `locate_teplate` to be child theme friendly
    return locate_template("{$file}.php") ? : $template;
  }

  return $template;

});

How it works

When you visit an url on a WordPress site, WordPress translate that url into a set of query arguments, and trigger a database query using them.

There are different types of query, for a page, for an archive, for a post, and so on. Look at Conditional Tags page on Codex, there is an exhaustive description of all the query types.

In your case you need to target single query type, because you want to change the template used whn a single CPT is required.

After a query is triggered, WordPress looks into theme folder to find a template to use to display query results. Look at template hierarchy to understand which file is used to each type of query.

When a file is found, before actually include that file, WordPress filter it using 2 filters.

In code above, I used the 'single_template' filter to change the template WordPress will load, returning a different template from a callback attacched to that filter.

However, that filter is triggered for every single request, even for standard posts and other CPTs, so before change the template I checked if current queried post is one of the CPT we want target. To obtain the current queried post I used [get_queried_object()][6] that in singular requests returns the post object.

If current post is not of target post type, I just return the file WordPress found, without altering it.

If current post is one of target post type, I build the template name looking at the post_parent attribute of the post: if the post has a parent I build 'clients_projects_child.php' if the post has not a parent I return 'clients_projects_parent.php'.

Before actually returning the template file, I use locate_template to see if in theme (or in child theme) that template file exists or not. If it exists I return it, in this way WordPress instead of loading the default template load the custom template, if the template doesn’t exists I return the default template, that is the one WordPress found.