Using ACF values in nested WP queries for CPT with date values in the past

Your current meta query embodies the logic

IF event_end IN range 
OR event_start IN range

You need to account for the conditions of event_end‘s presence separately:

IF event_end IN range
OR ( event_end NOT EXISTS AND event_start IN range )

Immediately adjacent nested clauses with the same AND/OR relation can be combined, which might make things a bit more readable.

a AND ( b AND ( c OR d ) ) === a AND b AND ( c OR d )
a OR ( b OR ( c AND d ) ) === a OR b OR ( c AND d )

You might also be able to name your clauses in order to order the results by which was used – but I haven’t tested this.

All of the above in practice:

$past_args = array(
  'post_type'  => 'event',
  'meta_query' => array(
    'relation' => 'AND',
    array(
      'relation'   => 'OR',
      // check to see if end date has been set and is in range
      'end_clause' => array(
        'key'     => 'end_date',
        'compare' => 'BETWEEN',
        'type'    => 'NUMERIC',
        'value'   => array($past, $now),
      ),
      // if no end date has been set use event/start date
      array(
        'relation' => 'AND',
        array(
          'key'     => 'end_date',
          'compare' => 'NOT EXISTS',
        ),
        'start_clause' => array(
          'key'     => 'event_date',
          'compare' => 'BETWEEN',
          'type'    => 'NUMERIC',
          'value'   => array($past, $now),
        ),
      ),
    ),
    array(
      'key'   => 'event_type',
      'value' => array('Singlar', 'Multi-Day', 'Series'),
    ),
    array(
      'key'   => 'include_in_past_events',
      'value' => '1',
    )
  ),
  // 'meta_key'      => 'event_date',// not needed when ordering by clause name.
  'orderby'       => 'end_clause start_clause',
  'order'         => 'DESC',
  'nopaging'      => false,
  'posts_per_page'=> '8',
);